WPF Combobox - изменен результат источника данных в пустом ItemsSource - PullRequest
0 голосов
/ 20 февраля 2020

Я делаю простую привязку Combobox на странице:

XAML:

 <ComboBox x:Name="Cmb_test"  Grid.Column="2" Grid.Row="2" HorizontalAlignment="Left"  ItemsSource="{Binding}" />

CODE позади:

private void Page_Loaded(object sender, RoutedEventArgs e)
{
     //Binding of label works fine everytime
     My_label.Content = dt.Rows[0]["Column1"];

     Cmb_test.DataContext = dt.DefaultView;
     Cmb_test.SelectedValuePath = dt.Columns[3].ToString();
     Cmb_test.DisplayMemberPath = dt.Columns[4].ToString();

     //Just a check to see whether DataTable really has changed
     Console.WriteLine(dt.Rows.Count.ToString());
 }

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

Код для закрытия моей страницы, для добавления:

CODE в том же самом Страница в виде списка:

private void BtnClose_Click(object sender, RoutedEventArgs e)
{
      Cmb_test.ItemsSource = null;
      Cmb_test.DataContext = null;

      var main_window = Application.Current.MainWindow;
      var frame = (main_window as MainWindow).My_Frame;
      frame.Content = null;

}

Код в MainWindow:

private void My_Frame_Navigated(object sender, NavigationEventArgs e)
{
     if (My_Frame.Content == null)
     {
        My_Frame.RemoveBackEntry();
     }
}

РЕДАКТИРОВАТЬ - еще одна попытка:

XAML:

  <Page.Resources>
        <CollectionViewSource x:Key="My_source"/>
    </Page.Resources>

  <ComboBox x:Name="Cmb_test" ItemsSource="{Binding Source={StaticResource My_source}}" DisplayMemberPath="Column1"/>

КОД позади:

 private void Page_Loaded(object sender, RoutedEventArgs e)
        {

            var combo_datasource = new CollectionViewSource();
            combo_datasource = (CollectionViewSource)this.FindResource("seznamVrstEvidenc");
            combo_datasource.Source = Tabele.dt_Sifrant.DefaultView;

        }

Что здесь происходит, как я могу исправить выпадающий список, чтобы каждый раз показывать его элементы?

Ответы [ 2 ]

1 голос
/ 20 февраля 2020

Вы не привязываете свой ComboBox ни к чему

<ComboBox x:Name="Cmb_test" [...] ItemsSource="{Binding}" />

У вас должна быть какая-то коллекция

<ComboBox x:Name="Cmb_test" [...] ItemsSource="{Binding MyList}" />

Глядя на остальную часть своего кода, кажется, что вы «вручную связать» ComboBox с таблицей данных. Затем вы можете создать Binding программно , который связывает ComboBox ItemsSource с DataTable DefaultView.

Однако существует проблема, если то, что вы имеете в виду под «DataTable изменен», выглядит как

dt = new DataTable();

или

dt = Db.GetTable();

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

Другим способом решения этой проблемы может быть установка ComSBox ItemsSource каждый раз, когда у вас появляется новый DataTable.

Надеюсь, я вам помог.

---- ----- ОБНОВЛЕНИЕ --------

После моего комментария я бы go с реализацией INotifyPropertyChanged для класса, который хранит DataTable dt.

public class ThatParticulareClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {  
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    // [...] all the other stuff

    public void MethodThatUpdateDataTable()
    {
        // Update DataTable
        NotifyPropertyChanged(nameof(dt));
    }
}

Это должно сработать. Если ваши изменения в объекте DataTable пришли только от пользователя (из представления), вам следует зарегистрироваться в элементе управления, который предоставляет DataTable конечное событие редактирования (что-то вроде DataGrid.RowEditEnding). В этот момент вы вызываете NotifyPropertyChanged (nameof (dt)); (Убедитесь, что этот вызов из того же класса, который содержит DataTable dt)

Реализация

0 голосов
/ 20 февраля 2020

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

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

1.) Создать класс Model . Здесь вы определяете свои столбцы DataTable и выставляете их как свойства. Этот класс должен быть унаследован от INotifyPropertyChanged :

 class Test_Model : INotifyPropertyChanged
 {
        private string col1;
        private string col2;

        public string Col1
        {
            get
            {
                return col1;
            }
            set
            {
                col1 = value;
                OnPropertyChanged("Col1");
            }
        }
        public string Col2
        {
            get
            {
                return col2;
            }
            set
            {
                col2 = value;
                OnPropertyChanged("Col2");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
   }

2.) Создайте класс Viev_Model . Здесь вы создаете IList (типа Test_Model) и заполняете его. с DataTable я использовал для этого LINQ - это тоже было проблемой. Затем вы снова предоставляете свойство типа IList, чтобы использовать его в качестве источника данных:

 class Test_ViewModel
 {
        private IList<Test_Model> _comboData;

        public Test_ViewModel()
        {
            _comboData = dt.AsEnumerable().
                Select(row => new Test_Model
                {
                    Col1 = row.Field<string>(0),
                    Col2 = row.Field<string>(1)
                }).ToList();
        }

        public IList<Test_Model> ComboData
        {
            get { return _comboData; }
            set { _comboData = value; }
        }
  }

3.) В своем окне или странице присвойте DataContext классу View_Model . Это делается в конструкторе, например так:

 public partial class My_Page: Page
 {
        public My_Page()
        {
            InitializeComponent();
            this.DataContext = new Test_ViewModel(); //assign ViewModel class
        }

        //...
  }

4.) Привязать комбинированный список к классу View_Model :

  <ComboBox x:Name="Cmb_Test" ItemsSource="{Binding Path= ComboData}" 
  DisplayMemberPath="Col1" SelectedValuePath="Col1" SelectedIndex="0"/>

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...