0

Идея такая. У меня есть производство, в datagrid вывожу данные с базы. Во время этого производства были простои. Внутри datagrid производства пытаюсь реализовать datagrid простоев связанных с производством. Путём нажатия на строку datagrid, получить данные из этой строки и с помощью entity framework отправить запрос в базу и выдать простои(в данный момент у меня просто SQL запросы). В идеале конечно сразу получить простои которые относятся к производству. Это мой код оформленный в UserControl

    <DataGrid materialDesign:ScrollBarAssist.ButtonsVisibility="Visible" materialDesign:ScrollBarAssist.ThumbCornerRadius="10" 
IsReadOnly="True" 
x:Name="References" 
AutoGenerateColumns="False"
IsEnabled="{Binding IsChecked, ElementName=EnableListBox}" 
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch"
FontSize="{DynamicResource GlobalFontSize}"
Width="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
MinWidth="900">
                            <DataGrid.Columns>
                                <DataGridTextColumn
                        Header="Date"
                        MaxWidth="110"
                        Width="*" 
                        Binding="{Binding Date}"/>
                                <DataGridTextColumn
                        Header="Part"
                        MaxWidth="260"
                        Width="*" 
                        Binding="{Binding Part}"/>
                                <DataGridTextColumn
                        Header="Start"
                        MaxWidth="93"
                        Width="*" 
                        Binding="{Binding Start}"/>
                                <DataGridTextColumn
                        Header="End"
                        MaxWidth="93"
                        Width="*" 
                        Binding="{Binding End}"/>
                                <DataGridTextColumn
                        Header="Прод. мин"
                        MaxWidth="110"
                        Width="*" 
                        Binding="{Binding ProdLength , StringFormat={}{0} Мин}"/>
                            &lt;DataGridTextColumn
                    Header=&quot;SPH&quot;
                    MaxWidth=&quot;75&quot;
                    Width=&quot;*&quot; 
                    Binding=&quot;{Binding SPH}&quot;/&gt;
                            &lt;DataGridTextColumn
                    Header=&quot;Defect Ratio&quot;
                    MaxWidth=&quot;115&quot;
                    Width=&quot;*&quot; 
                    Binding=&quot;{Binding DefRatio, StringFormat={}{0} %}&quot;/&gt;
                            &lt;DataGridTextColumn
                    Header=&quot;Net Util Rate&quot;
                    MaxWidth=&quot;120&quot;
                    Width=&quot;*&quot; 
                    Binding=&quot;{Binding NetUtilRate, StringFormat={}{0} %}&quot;/&gt;
                            &lt;DataGridTextColumn
                    Header=&quot;OEE&quot;
                    MaxWidth=&quot;115&quot;
                    Width=&quot;*&quot; 
                    Binding=&quot;{Binding OEE, StringFormat={}{0} %}&quot;/&gt;

                        &lt;/DataGrid.Columns&gt;
                        &lt;DataGrid.RowDetailsTemplate&gt;
                            &lt;DataTemplate&gt;

                                &lt;DataGrid IsReadOnly=&quot;True&quot; ItemsSource=&quot;{Binding DataContext.Downtimes, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}&quot; AutoGenerateColumns=&quot;False&quot; Name=&quot;grid1&quot;&gt;
                                    &lt;DataGrid.Columns&gt;
                                        &lt;DataGridTextColumn Header=&quot;Date&quot; Binding=&quot;{Binding Date1}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Length&quot; Binding=&quot;{Binding Length}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Part&quot; Binding=&quot;{Binding Part}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Respons&quot; Binding=&quot;{Binding Respons}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;ReasonComent&quot; Binding=&quot;{Binding ReasonComent}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Reason&quot; Binding=&quot;{Binding Reason}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Equipment&quot; Binding=&quot;{Binding Equipment}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;Side&quot; Binding=&quot;{Binding Side}&quot;/&gt;
                                        &lt;DataGridTextColumn Header=&quot;CommentMNTC&quot; Binding=&quot;{Binding CommentMNTC}&quot;/&gt;

                                    &lt;/DataGrid.Columns&gt;
                                &lt;/DataGrid&gt;
                            &lt;/DataTemplate&gt;
                        &lt;/DataGrid.RowDetailsTemplate&gt;
                    &lt;/DataGrid&gt;

когда я выбираю дату на календаре загружается список Производств,

введите сюда описание изображения

внутри каждого Производства вложен датагрид с Простоями, но Простои выгружаются все по всем производствам. Как сделать, чтобы простои вложенные выгружались только если Part производства = Part простоя

введите сюда описание изображения

Ниже мой класс

namespace Press_Shop_NMGR.ViewModel {
    public class Productions {
        public string Zn {
            get; set;
        }
        public string Slivers {
            get; set;
        }
        public object Hosh {
            get;
            internal set;
        }
        public object Scratch {
            get;
            internal set;
        }
        public object Oil {
            get;
            internal set;
        }
        public object Wave {
            get;
            internal set;
        }
        public object Wrinkle {
            get;
            internal set;
        }
        public object Material {
            get;
            internal set;
        }
        public object HoshPQA {
            get;
            internal set;
        }
        public object DefectPL {
            get;
            internal set;
        }
        public object DefectDMTNC {
            get;
            internal set;
        }
        public object SplitDMTNC {
            get;
            internal set;
        }
        public string SplitPQA {
            get;
            internal set;
        }
        public string ScrapPQA {
            get;
            internal set;
        }
        public string ScrapPL {
            get;
            internal set;
        }
        public string ScrapDMTNC {
            get;
            internal set;
        }
        public string ScrapNEPE {
            get;
            internal set;
        }
        public object SingleDefect {
            get;
            internal set;
        }
        public object MissedDefect {
            get;
            internal set;
        }
        public object TrailZn {
            get;
            internal set;
        }
        public object TrailSlivers {
            get;
            internal set;
        }
        public object TrailHosh {
            get;
            internal set;
        }
        public object TrailScratch {
            get;
            internal set;
        }
        public object TrailOil {
            get;
            internal set;
        }
        public object TrailWave {
            get;
            internal set;
        }
        public object TrailWrinkle {
            get;
            internal set;
        }
        public object TrailMaterial {
            get;
            internal set;
        }
        public object TrailHoshPQA {
            get;
            internal set;
        }
        public object TrailDefectPL {
            get;
            internal set;
        }
        public object TrailDefectDMTNC {
            get;
            internal set;
        }
        public object TrailSplitDMTNC {
            get;
            internal set;
        }
        public object TrailScrapDMTNC {
            get;
            internal set;
        }
        public object TrailScrapPL {
            get;
            internal set;
        }
        public object TrailSingleDefect {
            get;
            internal set;
        }
        public object TrailMissedDefect {
            get;
            internal set;
        }
        public object Part {
            get; internal set;
        }
        public object Start {
            get; internal set;
        }
        public string End {
            get; internal set;
        }
        public string Date {
            get; internal set;
        }
        public object SPH {
            get; internal set;
        }
        public object ProdLength {
            get; internal set;
        }
        public object Plan {
            get; internal set;
        }
        public object Fact {
            get; internal set;
        }
        public object Ok {
            get; internal set;
        }
        public object DefRatio {
            get; internal set;
        }
        public object NetUtilRate {
            get; internal set;
        }
        public string OEE {
            get; internal set;
        }
        public TimeSpan aTime {
            get;
            internal set;
        }
        public TimeSpan bTime {
            get;
            internal set;
        }
}

public class Downtimes {

    public string Date1 {
        get; set;
    }
    public string CommentProduction {
        get; set;
    }
    public string Respons {
        get; set;
    }
    public string Reason {
        get; set;
    }
    public string Part {
        get; set;
    }
    public string Equipment {
        get; set;
    }
    public string Side {
        get; set;
    }
    public string CommentMNTC {
        get; set;
    }
    public string ReasonComent {
        get; set;
    }
    public string Date2 {
        get; set;
    }
    public string Length {
        get;
        set;
    }
    public string Title {
        get;
        internal set;
    }
}

}

ну и сам код

public partial class ProductionView : UserControl {
    public string connection = @&quot;Provider=Microsoft.ACE.OLEDB.12.0; Data Source=PressShop.accdb&quot;; // путь к базе данных

    public ProductionView () {

        InitializeComponent ();
        DataContext = this;
    }

    public ObservableCollection&lt;Downtimes&gt; Downtimes {
        get; set;
    }
    public ObservableCollection&lt;Productions&gt; Productions {
        get; set;
    }

    public async void DataChanged (object sender, MouseButtonEventArgs e) {

        if ( Mouse.Captured is CalendarItem )
            Mouse.Capture (null);


        await Task.Delay (2000);
        if ( DateReport.SelectedDates.Count &gt; 0 ) {

            var start = ( DateReport.SelectedDates.Min () ).ToString (&quot;MM/dd/yyyy&quot;, CultureInfo.InvariantCulture) + &quot; 07:25:00&quot;;
            var end = ( DateReport.SelectedDates.Max () ).ToString (&quot;MM/dd/yyyy&quot;, CultureInfo.InvariantCulture) + &quot; 16:00:00&quot;;

            var sql =
                &quot;SELECT ref_summary.ref_start, ref_summary.ref_end, &quot; +
                &quot;parts.part, ref_summary.ref_plan, ref_summary.ref_actual, ref_summary.ref_ok, &quot; +
                &quot;ref_zn, ref_trailzn, &quot; +
                &quot;ref_slivers, ref_trailslivers, &quot; +
                &quot;ref_hosh, ref_trailhosh, &quot; +
                &quot;ref_scratch, ref_trailscratch, &quot; +
                &quot;ref_def_from_oil, ref_trailfrom_oil, &quot; +
                &quot;ref_wave, ref_trailwave, &quot; +
                &quot;ref_wrinkle, ref_trailwrinkle, &quot; +
                &quot;ref_def_material1, ref_trailmaterial1, &quot; +
                &quot;ref_def1, ref_traildef1, &quot; +
                &quot;ref_def2, ref_traildef2, &quot; +
                &quot;ref_def3, ref_traildef3, &quot; +
                &quot;ref_split, ref_trailsplit, &quot; +
                &quot;ref_miss_grip, &quot; +
                &quot;ref_def_material2, &quot; +
                &quot;ref_def4, ref_traildef4, &quot; +
                &quot;ref_def5, ref_traildef5, &quot; +
                &quot;ref_def6, &quot; +
                &quot;ref_single, ref_trailsingle, &quot; +
                &quot;ref_missed, ref_trailmissed &quot; +
                &quot;FROM ref_summary INNER JOIN parts ON ref_summary.ref_part = parts.id &quot; +
                &quot;WHERE ref_start BETWEEN #&quot; + start + &quot;# AND #&quot; + end + &quot;# &quot; +
                &quot;ORDER BY ref_summary.ref_start&quot;;

            OleDbConnection conn = new OleDbConnection (connection);
            conn.Open ();
            OleDbCommand command = new OleDbCommand ();
            command.CommandText = sql;
            command.Connection = conn;
            OleDbDataReader read = command.ExecuteReader ();

            if ( Productions == null )
                Productions = new ObservableCollection&lt;Productions&gt; ();

            while ( read.Read () ) {
                Productions.Add (new Productions {
                    Zn = read[6].ToString (),
                    Slivers = read[8].ToString (),
                    Hosh = read[10].ToString (),
                    Scratch = read[12].ToString (),
                    Oil = read[14].ToString (),
                    Wave = read[16].ToString (),
                    Wrinkle = read[18].ToString (),
                    Material = read[20].ToString (),
                    HoshPQA = read[22].ToString (),
                    DefectPL = read[24].ToString (),
                    DefectDMTNC = read[26].ToString (),
                    SplitDMTNC = read[28].ToString (),
                    SplitPQA = read[30].ToString (),
                    ScrapPQA = read[31].ToString (),
                    ScrapDMTNC = read[32].ToString (),
                    ScrapPL = read[34].ToString (),
                    ScrapNEPE = read[36].ToString (),
                    SingleDefect = read[37].ToString (),
                    MissedDefect = read[39].ToString (),

                    TrailZn = read[7],
                    TrailSlivers = read[9],
                    TrailHosh = read[11],
                    TrailScratch = read[13],
                    TrailOil = read[15],
                    TrailWave = read[17],
                    TrailWrinkle = read[19],
                    TrailMaterial = read[21],
                    TrailHoshPQA = read[23],
                    TrailDefectPL = read[25],
                    TrailDefectDMTNC = read[27],
                    TrailSplitDMTNC = read[29],
                    TrailScrapDMTNC = read[33],
                    TrailScrapPL = read[35],
                    TrailSingleDefect = read[38],
                    TrailMissedDefect = read[40],

                    Date = Convert.ToDateTime (read[0].ToString ()).ToShortDateString (),
                    Part = read[2].ToString (),
                    Start = Convert.ToDateTime (read[0].ToString ()).ToLongTimeString (),
                    End = Convert.ToDateTime (read[1].ToString ()).ToLongTimeString (),
                    aTime = TimeSpan.Parse (Convert.ToDateTime (read[0].ToString ()).ToLongTimeString ()),
                    bTime = TimeSpan.Parse (Convert.ToDateTime (read[1].ToString ()).ToLongTimeString ()),
                    ProdLength = ( ( TimeSpan.Parse (Convert.ToDateTime (read[1].ToString ()).ToLongTimeString ()) - TimeSpan.Parse (Convert.ToDateTime (read[0].ToString ()).ToLongTimeString ()) ).TotalSeconds ) / 60,
                    Plan = read[3].ToString (),
                    Fact = read[4].ToString (),
                    Ok = read[5].ToString (),
                    DefRatio = read[6].ToString (),
                    NetUtilRate = read[8].ToString (),
                    OEE = read[8].ToString (),
                    SPH = Convert.ToInt32 (read[6].ToString ()) * Convert.ToInt32 (read[12].ToString ()),
                });

                var Part = read[2].ToString ();
                using ( var con = new OleDbConnection (connection) ) {

                    con.Open ();
                    Console.WriteLine (&quot;select dt_date,dt_length,dt_comment,dt_response,dt_reason,dt_part,dt_equip,dt_side,dt_comment_mntc,dt_reason_break,dt_Edate,parts.part FROM downtime_summary INNER JOIN parts ON downtime_summary.dt_part = parts.id WHERE parts.part='&quot; + Part + &quot;' AND dt_date BETWEEN #&quot; + start + &quot;# AND #&quot; + end + &quot;# &quot;);
                    using ( var sqlCom = new OleDbCommand (&quot;select dt_date,dt_length,dt_comment,dt_response,dt_reason,dt_part,dt_equip,dt_side,dt_comment_mntc,dt_reason_break,dt_Edate,parts.part FROM downtime_summary INNER JOIN parts ON downtime_summary.dt_part = parts.id WHERE parts.part='&quot; + Part + &quot;' AND dt_date BETWEEN #&quot; + start + &quot;# AND #&quot; + end + &quot;# &quot;, con) ) {
                        sqlCom.ExecuteNonQuery ();
                        var dataAdapter = new OleDbDataAdapter (sqlCom);
                        var dataSet = new DataSet ();
                        dataAdapter.Fill (dataSet, &quot;downtime_summary&quot;);

                        if ( Downtimes == null )
                            Downtimes = new ObservableCollection&lt;Downtimes&gt; ();

                        foreach ( DataRow dr in dataSet.Tables[0].Rows ) {

                            Downtimes.Add (new Downtimes {
                                Date1 = dr[0].ToString (),
                                Length = dr[1].ToString (),
                                CommentProduction = dr[2].ToString (),
                                Respons = dr[3].ToString (),
                                Reason = dr[4].ToString (),
                                Part = dr[11].ToString (),
                                Equipment = dr[6].ToString (),
                                Side = dr[7].ToString (),
                                CommentMNTC = dr[8].ToString (),
                                ReasonComent = dr[9].ToString (),
                                Date2 = dr[10].ToString ()
                            });
                        }
                    }
                }
            }
            References.ItemsSource = Productions;
        }

    }
}

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

  • 1
    Где находится DowntimesCollection? Внутри того класса, который указан как ItemsSource для основного DataGrid? Не увидел, кстати, его указания в XAML, зато увидел x:Name="References", что приводит к мысли, что вы используете контролы в коде, что не есть хорошо. – EvgeniyZ Dec 08 '21 at 23:14
  • Да я сейчас переделываю эту часть кода где используются контролы. Сейчас не у компьютера, завтра буду продолжать. Может у вас есть на примете как правильно можно было бы организовать такой вывод данных. Я сколько гуглил, не нахожу подобного рода решения. – Александр Фелюгин Dec 09 '21 at 14:42
  • @EvgeniyZ может мы сможем договориться с вами) чтобы быть полезными друг другу, я только учусь и готов вознаградить) – Александр Фелюгин Dec 09 '21 at 14:53

1 Answers1

3

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

Смотрите, первым делом в WPF надо наладить систему привязок (Binding), это основа основ всего проекта, старайтесь не использовать в C# коде контролы через имена, не создавайте их там, не храните, ведь они для этого попросту не предназначены и вместо того, чтоб использовать один класс с несколькими свойствами, вы вечно дергаете элемент, который содержит в себе кучу лишнего (цвет, стиль, триггеры и пр.), что попросту будет лишним. Сразу вот разделите UI и данные на два лагеря, которые с собой почти не контактируют. Чтож, приступим...

  1. Зададим окну DataContext - это некий источник данных, в котором UI и все его внутренние объекты будут искать свойства для привязки. По хорошему, это делать так, но для простоты примера я весь код буду писать прям в классе окна (что не есть хорошо!!).

     public MainWindow()
     {
         InitializeComponent();
         DataContext = this;
     }
    

    Тут как видите, задаем простому свойству значение, где this - это текущий класс (MainWindow).

  2. Данные - нам нужны два класса, допустим пусть это будет "человек" и "задача человека", будем делать некий список дел.

    public record PersonTask(int Id, string Title, string Description);
    public record Person(int Id, string Name, int Age, IEnumerable<PersonTask> Tasks);
    

    record - это, по сути, тот же класс, только в неком сокращенном виде. Вам наверно надо будет сделать полноценные классы, с методами и прочим, в моем случае достаточно и этого.

  3. Свойства привязки - в WPF привязка работает только к публичным свойствам, если у вас будет нечто другое, то попросту не увидите данные в UI, а в логе будет ошибка "не удалось найти публичное свойство". Следите за этим! Сейчас наша цель, это сделать свойство, которое будет содержать в себе список всех людей.

     public Person[] People { get; } = new Person[]
     {
         new(1, "Вася", 24, new PersonTask[]
         {
             new(11, "Помыть полы", "Очень грязные!"),
             new(12, "Перекусить", "Голоден..."),
         }),
         new(2,"Таня", 16, new PersonTask[]
         {
             new(21, "Цветы", "Полить, протереть, удобрить"),
             new(22, "Собака", "Погулять, покормить"),
         })
     };
    

    Как видите, тут простой массив, который сразу имеет в себе нужные данные. В вашем случае наверно эти данные будут поступать постепенно, а значит вам нужна будет коллекция, которая реализует INotifyCollectionChanged, ведь именно эти интерфейсы (для свойств INotifyPropertyChanged) оповещают UI об изменениях данных. В C# уже есть коллекция, которая из коробки реализует данный интерфейс, звать ее ObservableCollection<T>, либо BindingList<T>. Так что, если у вас данные будут поступать в коллекцию после ее инициализации, то используйте одну из перечисленных выше коллекций, а не простой массив.

  4. Интерфейс - в вашем XAML, по сути, все правильно, задаем RowDetailsTemplate в нужным видом. Получаем примерно следующее:

     <DataGrid ItemsSource="{Binding People}" AutoGenerateColumns="False">
         <DataGrid.Columns>
             <DataGridTextColumn Header="ID" Binding="{Binding Id}" />
             <DataGridTextColumn Header="Имя" Binding="{Binding Name}" />
             <DataGridTextColumn Header="Возраст" Binding="{Binding Age}" />
         </DataGrid.Columns>
         <DataGrid.RowDetailsTemplate>
             <DataTemplate>
                 <DataGrid ItemsSource="{Binding Tasks}" AutoGenerateColumns="False">
                     <DataGrid.Columns>
                         <DataGridTextColumn Binding="{Binding Id}"/>
                         <DataGridTextColumn Binding="{Binding Title}"/>
                         <DataGridTextColumn Binding="{Binding Description}"/>
                     </DataGrid.Columns>
                 </DataGrid>
             </DataTemplate>
         </DataGrid.RowDetailsTemplate>
     </DataGrid>
    

Все, запускаем и смотрим:

Result Result open

Вот данные у нас успешно и отобразились, со всеми привязками и другими наворотами.

Теперь давайте поговорим почему не отображалось у вас?
Код вы нам не показали, но предположу, что привязанное свойство DowntimesCollection было за пределами того класса, который указан в виде ItemsSource для главного DataGrid. Обратите внимание на мой пример, у меня класс человека содержит в себе свойство с задачами. В привязках WPF ведь как все работает: если вы внутри контрола разместили еще контрол, то источником данных для внутреннего контрола будет тот объект, что указан как источник данных для внешнего (это если коллекция).

Как быть, если надо привязать внутренний DataGrid к списку за пределами внешнего? - в таком случае надо перейти на уровень выше по привязками, найти "родителя" и у его DataContext забрать нужное нам свойство для привязки. В моем примере это примерно так:

ItemsSource="{Binding DataContext.Tasks, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"

То есть я задаю привязку к DataContext.Tasks, а также указывают RelativeSource в режиме FindAncestor (найти предка), с указанием типа "предка" AncestorType=DataGrid.

EvgeniyZ
  • 15,694
  • 1
    спасибо тебе! я всё не перестану удивляться доброте нашего народа! я реализовал то что хотел благодаря твоему решению) – Александр Фелюгин Dec 10 '21 at 12:31
  • я обновил вопрос, добавил код, подскажите пожалуйста где мои ошибки) – Александр Фелюгин Dec 16 '21 at 17:22
  • @АлександрФелюгин А как это относится к первоначальному вопросу? Вот вы добавили туда информацию, часть переделали, из-за чего мой ответ сейчас по сути стал бесполезным, не в тему, ведь суть вопроса другая. Так делать плохо... Ну а так, я бы сказал, что ваша проблема в самом коде, у вас все в одну кучу, вы не слушаете меня, вы дальше лепите свои костыли) Вот, к примеру я самым первым комментарием под вопросом написал зато увидел x:Name="References", далее ответом показал, как надо. Почему у вас в коде по-прежнему References.ItemsSource = Productions;? – EvgeniyZ Dec 16 '21 at 17:38
  • Также по коду еще кучу мест проблемных найти можно (например Downtimes = new ObservableCollection<Downtimes> ();, где Downtimes не реализует INPC, из за чего данные в коде UI не будут обновлятся.). Ну а так, если отвечать на "почему берет всех, а не только нужного" - наверно дело в запросе, в тех данных, что вы берете из базы? Смотрите что выдает строка dataSet.Tables[0].Rows. – EvgeniyZ Dec 16 '21 at 17:41
  • ваш ответ по прежнему остался решением, просто я воспользовался лишь его частью, пробовал реализовать как у вас используя свои классы, и не получалось. В таблицу ничего не выводилось. Я понимаю что я тугой, потому что я учусь) А по поводу References.ItemsSource = Productions; я правда не знаю как сделать по другому( Во втором цикле где я вывожу запрос, он корректный, там меняется Part в запросе. Но коллекция общая получается в итоге а не к конкретной детали. – Александр Фелюгин Dec 16 '21 at 18:46
  • я вывел в консоль запрос sql а после dataSet.Tables[0].Rows и получаю, строку запроса с нужным Part а после System.Data.DataRowCollection ровно столько раз сколько простоев по данному Part. Тоесть всё верно получается, но на выходе я получаю общую коллекцию и делаю биндинг этой общей коллекции во вложенный датагрид. Напрашивается вывод, что нужно настроить биндинг главного датагрид, но я правда не догоняю как, сколько бы я не пересмотрел уроков и даже ваш пример подогнать не получилось. =( – Александр Фелюгин Dec 16 '21 at 19:25
  • @АлександрФелюгин я правда не знаю как сделать по другому - убрать эту строку и задать наверно привязку в XAML? <DataGrid ... ItemsSource = "{Binding Productions}">, все. Запомните просто раз и на всегда правило: в WPF все строится на привязках, у вас должно быть так, что вы в XAML полностью удаляете все, запускаете и ваша логика работает (без отображения естественно). То есть не должно быть каких либо x:Name и далее в коде name.Property = ..., нет, это грубое нарушение, особенно, если вы пишете по правилам MVVM (что по некоторым названиям вы пытаетесь сделать). – EvgeniyZ Dec 16 '21 at 19:34
  • По поводу проблемы, я кажется понял в чем она у вас. Опять же, из за того, что у вас все в одну кучу, вы сейчас страдаете... У вас есть некое событие, по которому вы грузите всю базу сразу в память, когда должны загрузить только то, что сейчас отображается. Также и внутренний DataGrid, вы привязываете SelectedItem к некому свойству, в его set вызываете метод, который подгрузит новые данные в коллекцию, к которой в свою очередь и будет привязан внутренний DataGrid. – EvgeniyZ Dec 16 '21 at 19:39
  • А по поводу "пробовал как у вас структуру, не получается" - плохо значит пробовали, не поняв суть. Вот представьте тело человека, у него есть внутри органы, сердце там, мозг, легкие и др. Вот тело - это один объект, оно отвечает только за свои функции (соединить все в одно целое и запустить), а каждый орган - это также отдельные объекты со своей логикой работы. Вот ваш код должен быть аналогичным этому примеру, где каждый класс, каждый метод, выполняет только одну, свою задачу. У вас вот сейчас в классе продуктов идет соединение с базой, оно за это должно отвечать? Нет. Так почему там? – EvgeniyZ Dec 16 '21 at 19:42