2016-01-03 2 views
0

У меня есть DataGrid, что его источником является база данных на основе базы данных. код не находится в MVVM.Динамическое обновление DataGridComboBoxColumn (не MVVM)

Теперь мне нужен источник DataGridComboBoxColumn для изменения на основе другого значения DataGridComboBoxColumn, которое находится в одном и том же DataGrid. Я уверен, что есть простое решение, но, тем не менее, он не может понять, как это сделать?

Мой код:

XAML:

<DataGridComboBoxColumn x:Name="active_idnt_deviceCmb" SelectedValueBinding="{Binding idnt_linked_io_device}" DisplayMemberPath="correct_idnt_active_logic_device" SelectedValuePath="idnt_active_device" Header="input id" Width="80"></DataGridComboBoxColumn> 
    <DataGridComboBoxColumn x:Name="active_device_addressCmb" ElementStyle="{StaticResource MyComboBoxStyle}" SelectedValueBinding="{Binding idnt_linked_io_device}" DisplayMemberPath="active_device_address" SelectedValuePath="active_device_address" Header="Relay Address" Width="65"><DataGridComboBoxColumn.EditingElementStyle> 
      <Style TargetType="{x:Type ComboBox}"> 
       <EventSetter Event="SelectionChanged" Handler="changeDeviceAddress" /> 
      </Style> 
    </DataGridComboBoxColumn.EditingElementStyle> 
</DataGridComboBoxColumn> 

CS:

private void changeDeviceAddress(object sender, SelectionChangedEventArgs e) 
{ 
    HelpDataSet.ACTIVE_IO_DEVICESDataTable dtActiveIo = new HelpDataSet.ACTIVE_IO_DEVICESDataTable(); 
    var comboBox = sender as ComboBox; 

    if (comboBox.SelectedValue != null) 
    { 
     AppHelp.ActiveIODeviceAdapter.ClearBeforeFill = true; 
     AppHelp.ActiveIODeviceAdapter.FillByIdntRelayAddress(dtActiveIo, comboBox.SelectedValue.ToString()); 
     active_idnt_deviceCmb.ItemsSource = dtActiveIo.DefaultView; 
    } 
} 

но меняет весь источник столбца, а не только в определенной ячейке в строке.

+4

Удалите все это и используйте надлежащее DataBinding. –

+0

@HighCore Как мне это сделать? – DasDas

+0

Возможно, вам будет интересно ознакомиться с [Обзор привязки данных] (https://msdn.microsoft.com/library/ms752347 (v = vs.100) .aspx). Это объяснит, как использовать ваш DataContext в ваших интересах , –

ответ

2

вот решение, которое вообще не использует подход MVVM, основанный на ориентированном на WPF поведении. Имейте в виду, что все модели просто представляют строки сетки данных, у них нет никаких дополнительных функций. Сбор исходной коллекции запускается в поведении с помощью комбинированного триггера выбора. Вот код: 1. XAML код:

<Window x:Class="ComboWithoutCodeBehind.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:comboWithoutCodeBehind="clr-namespace:ComboWithoutCodeBehind" 
    Title="MainWindow" Height="350" Width="525" x:Name="This"> 
    <Grid > 
     <DataGrid x:Name="SelectDataGrid" 
        ItemsSource="{Binding ElementName=This, Path=Persons}" HorizontalAlignment="Left" VerticalAlignment="Top" AutoGenerateColumns="False"> 
      <DataGrid.Columns> 
       <DataGridCheckBoxColumn x:Name="dgCheckBox" Header="Select" Width="45" Binding="{Binding IsChecked}"/> 
       <DataGridTextColumn Header="FIRST NAME" Width="125" Binding="{Binding FNAME}"/> 
       <DataGridTextColumn Header="LAST NAME" Width="125" Binding="{Binding LNAME}"/> 
       <DataGridTemplateColumn Header="Selection" Width="120"> 
        <DataGridTemplateColumn.CellTemplate> 
         <DataTemplate> 
          <Grid> 
           <Grid.ColumnDefinitions> 
            <ColumnDefinition></ColumnDefinition> 
            <ColumnDefinition></ColumnDefinition> 
           </Grid.ColumnDefinitions> 
           <ComboBox Grid.Column="0" x:Name="DataGridTemplateColumnComboBox" SelectedIndex="0" ItemsSource="{Binding ElementName=This, Path=ServersCollection}" 
             DisplayMemberPath="ServerName"></ComboBox> 
           <ComboBox Grid.Column="1" DisplayMemberPath="DbName"> 
            <i:Interaction.Behaviors> 
             <comboWithoutCodeBehind:ItemsSourcePosessingBehavior 
             SourceProvidingFactory="{Binding ElementName=This, Path=MainSourceProvidingFactory}" 
              SiblingComboBox="{Binding ElementName=DataGridTemplateColumnComboBox}"/> 
            </i:Interaction.Behaviors> 
           </ComboBox> 
          </Grid> 
         </DataTemplate> 
        </DataGridTemplateColumn.CellTemplate> 
       </DataGridTemplateColumn> 
      </DataGrid.Columns> 
     </DataGrid> 
    </Grid> 

2. Код позади, модели и заводской шифр:

public partial class MainWindow : Window 
{ 
    public static readonly DependencyProperty PersonsProperty = DependencyProperty.Register("Persons", 
     typeof (ObservableCollection<Person>), typeof (MainWindow), 
     new PropertyMetadata(default(ObservableCollection<Person>))); 

    public static readonly DependencyProperty MainSourceProvidingFactoryProperty = 
     DependencyProperty.Register("MainSourceProvidingFactory", typeof (SourceProvidingFactory), 
      typeof (MainWindow), new PropertyMetadata(default(SourceProvidingFactory))); 

    public ObservableCollection<Person> Persons 
    { 
     get { return (ObservableCollection<Person>)GetValue(PersonsProperty); } 
     set { SetValue(PersonsProperty, value); } 
    } 

    public SourceProvidingFactory MainSourceProvidingFactory 
    { 
     get { return (SourceProvidingFactory)GetValue(MainSourceProvidingFactoryProperty); } 
     set { SetValue(MainSourceProvidingFactoryProperty, value); } 
    } 

    public MainWindow() 
    { 
     MainSourceProvidingFactory = new SourceProvidingFactory(GetCollection); 
     InitSources(); 
     InitializeComponent(); 
    } 

    private ObservableCollection<DbDetails> GetCollection(object arg) 
    { 
     //you can perform your db relate logic here 
     var sereverDetails = arg as ServerDetails; 
     return sereverDetails == null ? null : new ObservableCollection<DbDetails>(sereverDetails.DbDetailses); 
    } 


    private void InitSources() 
    { 
     var l = new List<Person> 
     { 
      new Person {FNAME = "John", LNAME = "W"}, 
      new Person {FNAME = "George", LNAME = "R"}, 
      new Person {FNAME = "Jimmy", LNAME = "B"}, 
      new Person {FNAME = "Marry", LNAME = "B"}, 
      new Person {FNAME = "Ayalot", LNAME = "A"}, 
     }; 
     Persons = new ObservableCollection<Person>(l); 

     ServersCollection = new ObservableCollection<ServerDetails>(new List<ServerDetails> 
     { 
      new ServerDetails 
      { 
       ServerName = "A", 
       DbDetailses = new List<DbDetails> 
       { 
        new DbDetails {DbName = "AA"}, 
        new DbDetails {DbName = "AB"}, 
        new DbDetails {DbName = "AC"}, 
       } 
      }, 
      new ServerDetails 
      { 
       ServerName = "B", 
       DbDetailses = new List<DbDetails> 
       { 
        new DbDetails {DbName = "BA"}, 
        new DbDetails {DbName = "BB"}, 
        new DbDetails {DbName = "BC"}, 
       } 
      }, 
      new ServerDetails 
      { 
       ServerName = "C", 
       DbDetailses = new List<DbDetails> 
       { 
        new DbDetails {DbName = "CA"}, 
        new DbDetails {DbName = "CB"}, 
       } 
      } 
     }); 
    } 


    public ObservableCollection<ServerDetails> ServersCollection { get; set; } 
} 

public class SourceProvidingFactory 
{ 
    public SourceProvidingFactory(Func<object, ObservableCollection<DbDetails>> action) 
    { 
     GetCollection = action; 
    } 

    public Func<object, ObservableCollection<DbDetails>> GetCollection { get; set; } 
} 

public class Person : BaseObservableObject 
{ 
    private string _lName; 
    private string _fName; 
    private bool _checked; 

    public bool IsChecked 
    { 
     get { return _checked; } 
     set 
     { 
      _checked = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string LNAME 
    { 
     get { return _lName; } 
     set 
     { 
      _lName = value; 
      OnPropertyChanged(); 
     } 
    } 

    public string FNAME 
    { 
     get { return _fName; } 
     set 
     { 
      _fName = value; 
      OnPropertyChanged(); 
     } 
    } 
} 

public class ServerDetails : BaseObservableObject 
{ 
    private string _serverName; 

    public string ServerName 
    { 
     get { return _serverName; } 
     set 
     { 
      _serverName = value; 
      OnPropertyChanged(); 
     } 
    } 

    public List<DbDetails> DbDetailses { get; set; } 
} 

public class DbDetails : BaseObservableObject 
{ 
    private string _dbName; 

    public string DbName 
    { 
     get { return _dbName; } 
     set 
     { 
      _dbName = value; 
      OnPropertyChanged(); 
     } 
    } 
} 

3. Поведение Код:

public class ItemsSourcePosessingBehavior : Behavior<ComboBox> 
{ 

    public static readonly DependencyProperty SiblingComboBoxProperty = DependencyProperty.Register(
     "SiblingComboBox", typeof(ComboBox), typeof(ItemsSourcePosessingBehavior), new PropertyMetadata(default(ComboBox))); 

    public ComboBox SiblingComboBox 
    { 
     get { return (ComboBox)GetValue(SiblingComboBoxProperty); } 
     set { SetValue(SiblingComboBoxProperty, value); } 
    } 

    public static readonly DependencyProperty SourceProvidingFactoryProperty = DependencyProperty.Register(
     "SourceProvidingFactory", typeof (SourceProvidingFactory), typeof (ItemsSourcePosessingBehavior), new PropertyMetadata(default(SourceProvidingFactory))); 

    public SourceProvidingFactory SourceProvidingFactory 
    { 
     get { return (SourceProvidingFactory) GetValue(SourceProvidingFactoryProperty); } 
     set { SetValue(SourceProvidingFactoryProperty, value); } 
    } 


    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     SiblingComboBox.SelectionChanged += SiblingComboBoxOnSelectionChanged; 
     SiblingComboBox.Loaded += SiblingComboBoxOnLoaded; 
    } 

    private void SiblingComboBoxOnLoaded(object sender, RoutedEventArgs routedEventArgs) 
    { 
     AssociatedObject.ItemsSource = null; 
     var siblingCombo = sender as ComboBox; 
     InitAssociatedObjectItemsSource(siblingCombo); 
    } 


    private void SiblingComboBoxOnSelectionChanged(object sender, SelectionChangedEventArgs selectionChangedEventArgs) 
    { 
     AssociatedObject.ItemsSource = null; 
     var siblingCombo = sender as ComboBox; 
     InitAssociatedObjectItemsSource(siblingCombo); 
    } 

    private void InitAssociatedObjectItemsSource(ComboBox siblingCombo) 
    { 
     if (siblingCombo == null) 
     { 
      return; 
     } 
     if (SourceProvidingFactory == null) 
     { 
      return; 
     } 
     AssociatedObject.ItemsSource = SourceProvidingFactory.GetCollection(siblingCombo.SelectedItem); 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     SiblingComboBox.SelectionChanged -= SiblingComboBoxOnSelectionChanged; 
     SiblingComboBox.Loaded -= SiblingComboBoxOnLoaded; 
    } 
} 

Этот это полное решение, просто скопированное/прошедшее ... Буду рад помочь, если у вас возникнут проблемы с кодом.

С уважением.

+0

i dont want it of MVVM – DasDas

+0

@DasDas see updates – Ilan

+0

@DasDas, пожалуйста, ознакомьтесь с новым решением, оно основано на поведении wpf и подходе к коду. – Ilan

0

Я думаю, что это очень простая проблема, с которой мы сталкиваемся в таком сценарии. теперь, когда у вас нет проблем с отображением и привязкой, я просто напишу, что я думаю о проблеме.

Не используйте active_idnt_deviceCmb.ItemsSource, это сбросит все исходные коды Combobox. Вы хотите различную опцию в разных строках на основе другого значения столбца. Таким образом, вам нужно поддерживать отношения один к одному для каждой записи для каждого раскрывающегося списка.

Лучший способ сделать это - это то, что когда-либо класс привязан к записи, вам нужно создать много источников данных. если List<MyRecord> является ItemSource сетки затем создать класс, как:

public class MyRecord : INotifyPropertyChanged 
{  
    private string a; 
    public string A 
    { 
     get { return a; } 
     set { a = value; 
     OnPropertyChanged("A"); 
     OnPropertyChanged("SecondList"); 
     } 
    } 

    private string b; 
    public string B 
    { 
     get { return b; } 
     set { b = value; 
     OnPropertyChanged("B"); 
     } 
    } 

    private List<ComboBoxItem> firstList; 
    public List<ComboBoxItem> FirstList 
    { 
     get { return firstList; } 
     set { firstList = value; 
     OnPropertyChanged("FirstList"); 
     } 
    } 

    private List<ComboBoxItem> secondList; 
    public List<ComboBoxItem> SecondList 
    { 
     get { return secondList.Where(x=>x.value.StartsWith(A)).ToList(); } 
     set { secondList = value; 
     OnPropertyChanged("SecondList"); 
     } 
    } 


} 

PS: Первый столбец сетки связываются с А, второй с В, а firstlist и secondlist будет связываться с раскрывающимся обеих колонн. каждый раз, когда я выбираю значение в первом столбце, он будет возвращен в свойство A, и в этот момент я обновляю второй список (который также содержит логику фильтра, или вы можете вызывать логику фильтра и обновлять второй список отдельно).

Поскольку этот второй список связывается только с одной записью, только одно выпадающее меню будет сброшено.

XAML кода для понимания:

<DataGridComboBoxColumn x:Name="active_idnt_deviceCmb" 
            SelectedValuePath="value" 
            DisplayMemberPath="display"           
            SelectedValueBinding="{Binding A}"           
            Header="input id" Width="80"> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding Path=FirstList}" /> 
        </Style> 
        </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 
      <DataGridComboBoxColumn 
            SelectedValuePath="value" 
            DisplayMemberPath="display"           
            SelectedValueBinding="{Binding B}" 
            Header="Relay Address" Width="65"> 
       <DataGridComboBoxColumn.EditingElementStyle> 
        <Style TargetType="{x:Type ComboBox}"> 
         <Setter Property="ItemsSource" Value="{Binding Path=SecondList}" />         
        </Style> 
       </DataGridComboBoxColumn.EditingElementStyle> 
      </DataGridComboBoxColumn> 

Выпадающего класс источника пункта (только чтобы понять DataGridComboBoxColumn связывания):

public class ComboBoxItem 
{ 
    public ComboBoxItem(string a) 
    { 
     display = value = a; 
    } 

    public string display { get; set; } 

    public string value { get; set; } 
} 

надеюсь, вы будете в состоянии соответствовать этому коду в приложении. Главное - отношения «один к одному», что важно.

 Смежные вопросы

  • Нет связанных вопросов^_^