Привязка XAML к серверу SQL - PullRequest
0 голосов
/ 25 сентября 2011

У меня есть БД SQL Server со следующими таблицами и связями:

Работа, которая содержит много сессий. Сессии, которые содержат много перерывов.

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

В XAML я пытаюсь и преуспеваю при привязке заданий. Я получаю это, чтобы отфильтровать правильные сессии. Там нет проблем.

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

Я не использую (и не заинтересован в использовании) Linq2Sql, поскольку он создает слишком много дополнительных классов, которые раздувают мой код. Я просто использую прямую привязку данных.

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

Мой вопрос здесь: что я делаю не так? У меня сложилось впечатление, что, поскольку я могу успешно связывать и фильтровать сеансы, я должен иметь возможность делать то же самое с сеансами и перерывами фильтров. Но это не работает.

Я немного отчаиваюсь за помощью и оцениваю любые ответы.

РЕДАКТИРОВАТЬ: еще раз я включил примеры кода. Я не пытаюсь скрыть код для секретности и авторских прав. Это всего лишь упражнение, которое я делаю, чтобы учиться, поэтому я не возражаю опубликовать полный код. Но это очень долго. Поэтому я просто опубликую те части, которые я считаю актуальными. Если хочешь большего, просто спроси.

Для тех из вас, кто заинтересован в том, чтобы перейти к хорошей части, где есть проблемы, загляните под часть списка «Перерывы». Остальное просто для сравнения, чтобы помочь вам отладить. Ниже приведен также код C #, который поможет вам в дальнейшем. Опять же, посмотрите на часть списка, остальное только для отладки.

Ниже приведен соответствующий XAML

<!--Jobs List box - Works fine-->
<ListBox Name="lstJobs"  DockPanel.Dock="Top"
        MinWidth="150" MinHeight="200" MaxHeight="250"
        ScrollViewer.VerticalScrollBarVisibility="Visible"
        SelectionChanged="lstJobs_SelectionChanged"

        IsSynchronizedWithCurrentItem="True"
        DataContext="{Binding Tables[JobDetails]}"
        ItemsSource="{Binding}"
        >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                    <TextBlock Text="{Binding Path=Title}"/>
                    <TextBlock Text=" "/>
                    <TextBlock Text="{Binding Path=ID}"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<!--How Jobs listbox is bound to relevant fields in jobs table. This works fine-->
<TextBox    Text="{Binding        ElementName=lstJobs, Path=SelectedItem.ID,            UpdateSourceTrigger=PropertyChanged}" Name="txtJobNo"          Grid.Row="1"                 IsEnabled="False"/>
<TextBox    Text="{Binding        ElementName=lstJobs, Path=SelectedItem.Title,         UpdateSourceTrigger=PropertyChanged}" Name="txtJobTitle"       Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"/>
<TextBox    Text="{Binding        ElementName=lstJobs, Path=SelectedItem.Description,   UpdateSourceTrigger=PropertyChanged}" Name="txtJobDesc"        Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Grid.RowSpan="2"/>


<!--Sessions List box, Automatically filtered based on relationship (see last binding line). This works fine too-->
<ListBox Name="lstSessions" DockPanel.Dock="Top" MinWidth="150"
        MinHeight="200" MaxHeight="220"
        ScrollViewer.VerticalScrollBarVisibility="Visible"
        SelectionChanged="lstSessions_SelectionChanged"

        IsSynchronizedWithCurrentItem="True"
        DataContext="{Binding Path=Tables[JobDetails]}"
        ItemsSource="{Binding Path=relJobDetailsSessionDetails}"
        >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                    <TextBlock Text="{Binding Path=Title}" />
                    <TextBlock Text="{Binding Path=ID}" />
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<!--How Sessions listbox is bound to relevant fields in Sessions table. This works fine-->
<TextBox Name="txtSessionNo"          Text="{Binding ElementName=lstSessions, Path=SelectedItem.ID,            UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="0"/>
<TextBox Name="txtSessionTitle"       Text="{Binding ElementName=lstSessions, Path=SelectedItem.Title,         UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3"/>
<TextBox Name="txtSessionDesc"        Text="{Binding ElementName=lstSessions, Path=SelectedItem.Description,   UpdateSourceTrigger=PropertyChanged}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Grid.RowSpan="2"/>


<!--Breaks List box, Should be automatically filtered (it is), but it does not change when a job or session is selected. Why?? -->
<ListBox Name="lstBreaks" MinWidth="150" MinHeight="140" MaxHeight="140"
        ScrollViewer.VerticalScrollBarVisibility="Visible"
        SelectionChanged="lstBreaks_SelectionChanged"

        IsSynchronizedWithCurrentItem="True"
        DataContext="{Binding Path=Tables[SessionDetails]}"
        ItemsSource="{Binding Path=relSessionDetailsBreakDetails}"
        >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid>
                <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                    <TextBlock Text="{Binding Path=Title}" />
                    <TextBlock Text="{Binding Path=ID}" />
                </StackPanel>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

<!--How Breaks listbox is bound to relevant fields in Breaks table. This works fine as before-->
<TextBox Name="txtBreakNo"          Text="{Binding ElementName=lstBreaks, Path=SelectedItem.ID,            UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="0"/>
<TextBox Name="txtBreakTitle"       Text="{Binding ElementName=lstBreaks, Path=SelectedItem.Title,         UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"/>
<ComboBox Name="cbxBreakType"       Text="{Binding ElementName=lstBreaks, Path=SelectedItem.Description,     UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="3"/>

Ниже приведен код C # (опять же, выделенная часть - это разрывы, а остальное - просто для сравнения, поэтому вы можете сразу перейти к этому, если хотите):

//Connection String
string conString = "XYZ Works ok, no prob here";

//Data Adaptors for various tables
SqlDataAdapter daJobDetails = new SqlDataAdapter();
SqlDataAdapter daSessionDetails = new SqlDataAdapter();
SqlDataAdapter daBreakDetails = new SqlDataAdapter();

//The dataset to hold all of the data
DataSet dsDataSet = new DataSet();

//Step 1: Create Connection
SqlConnection conn = new SqlConnection(conString);

//Open Connection
conn.Open();


//Load Job Details Table - works fine.
daJobDetails.SelectCommand = new SqlCommand("Select * From JobDetails", conn);
daJobDetails.Fill(dsDataSet, "JobDetails");

//Load Session Details table - works fine.
daSessionDetails.SelectCommand = new SqlCommand("SELECT * FROM SessionDetails", conn);
daSessionDetails.Fill(dsDataSet, "SessionDetails");

//Relation: JobDetails.ID = SessionDetails.JobID. - Works fine
dsDataSet.Relations.Add("relJobDetailsSessionDetails",
    dsDataSet.Tables["JobDetails"].Columns["ID"],
    dsDataSet.Tables["SessionDetails"].Columns["JobID"]);


//**** Possible problem code *****
//Load Break Details table - could there be something wrong here.
daBreakDetails.SelectCommand = new SqlCommand("SELECT * FROM BreakDetails", conn);
daBreakDetails.Fill(dsDataSet, "BreakDetails");

//**** Possible problem code *****
//Relation: SessionDetails.ID = BreakDetails.SessionID - Could there be something wrong here
dsDataSet.Relations.Add("relSessionDetailsBreakDetails",
    dsDataSet.Tables["SessionDetails"].Columns["ID"],
    dsDataSet.Tables["BreakDetails"].Columns["SessionID"]);



//Set the DataContext to the DataSet
expJobs.DataContext = dsDataSet;


//Close connection
conn.Close();

1 Ответ

1 голос
/ 01 октября 2011

По запросу, здесь приведен полный случай воспроизведения.

Обновление: обновлено с помощью рабочего кода по вашей ссылке. Похоже, что ответ был привязан к отношению SelectedItem =>. Очень логично, на самом деле.

XAML:

<Window x:Class="WpfApplication2.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="MainWindow" Height="350" Width="525">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width=".5*"/>
            <ColumnDefinition Width=".5*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height=".33*"/>
            <RowDefinition Height=".33*"/>
            <RowDefinition Height=".33*"/>
        </Grid.RowDefinitions>
        <!--Jobs List box - Works fine-->
        <ListBox Name="lstJobs" Grid.Column="0" Grid.Row="0" 
             MinWidth="150"  
             MinHeight="200"  
             MaxHeight="250"          
             ScrollViewer.VerticalScrollBarVisibility="Visible"          
             SelectionChanged="lstJobs_SelectionChanged"           
             IsSynchronizedWithCurrentItem="True"          
             ItemsSource="{Binding Path=JobDetails}"                      
             >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                            <TextBlock Text="{Binding Path=ID}"/>
                            <TextBlock Text="{Binding Path=Title}"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <!--How Jobs listbox is bound to relevant fields in jobs table. This works fine-->
        <StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="0">
            <TextBox Text="{Binding ElementName=lstJobs, Path=SelectedItem.ID, UpdateSourceTrigger=PropertyChanged}"  
             Name="txtJobNo" Grid.Row="1" IsEnabled="False"/>
            <TextBox Text="{Binding ElementName=lstJobs, Path=SelectedItem.Title, UpdateSourceTrigger=PropertyChanged}"  
             Name="txtJobTitle" Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"/>
            <TextBox Text="{Binding ElementName=lstJobs, Path=SelectedItem.Description, UpdateSourceTrigger=PropertyChanged}"  
             Name="txtJobDesc" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Grid.RowSpan="2"/>
        </StackPanel>

        <!--Sessions List box, Automatically filtered based on relationship (see last binding line). This works fine too -->
        <ListBox Name="lstSessions" Grid.Column="0" Grid.Row="1" 
             DockPanel.Dock="Top"  
             MinWidth="150"          
             MinHeight="200"  
             MaxHeight="220"          
             ScrollViewer.VerticalScrollBarVisibility="Visible"          
             SelectionChanged="lstSessions_SelectionChanged"           
             IsSynchronizedWithCurrentItem="True"          
             ItemsSource="{Binding ElementName=lstJobs, Path=SelectedItem.relJobDetailsSessionDetails}" 
             >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                            <TextBlock Text="{Binding Path=Title}" />
                            <TextBlock Text="{Binding Path=ID}" />
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>


        <!--How Sessions listbox is bound to relevant fields in Sessions table. This works fine-->
        <StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="1">
            <TextBox Name="txtSessionNo" Text="{Binding ElementName=lstSessions, Path=SelectedItem.ID,  UpdateSourceTrigger=PropertyChanged}"  
             Grid.Row="1" Grid.Column="0"/>
            <TextBox Name="txtSessionTitle" Text="{Binding ElementName=lstSessions, Path=SelectedItem.Title, UpdateSourceTrigger=PropertyChanged}"  
             Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3"/>
            <TextBox Name="txtSessionDesc" Text="{Binding ElementName=lstSessions, Path=SelectedItem.Description, UpdateSourceTrigger=PropertyChanged}"  
             Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Grid.RowSpan="2"/>
        </StackPanel>

        <!--Breaks List box, Should be automatically filtered (it is), but it does not change when a job or session is selected. Why?? -->
        <ListBox Name="lstBreaks" Grid.Column="0" Grid.Row="2" 
             MinWidth="150"  
             MinHeight="140"  
             MaxHeight="140"          
             ScrollViewer.VerticalScrollBarVisibility="Visible"          
             SelectionChanged="lstBreaks_SelectionChanged"           
             IsSynchronizedWithCurrentItem="True"          
             ItemsSource="{Binding ElementName=lstSessions, Path=SelectedItem.relSessionDetailsBreakDetails}"          
             >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <StackPanel Orientation="Horizontal" Margin="3,0,3,0">
                            <TextBlock Text="{Binding Path=Title}" />
                            <TextBlock Text="{Binding Path=ID}" />
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <!--How Breaks listbox is bound to relevant fields in Breaks table. This works fine as before-->
        <StackPanel Orientation="Vertical" Grid.Column="1" Grid.Row="2">
            <TextBox Name="txtBreakNo" DockPanel.Dock="Bottom"  
             Text="{Binding ElementName=lstBreaks, Path=SelectedItem.ID, UpdateSourceTrigger=PropertyChanged}"  
             Grid.Row="2" Grid.Column="1"/>
            <TextBox Name="txtBreakTitle" DockPanel.Dock="Bottom" 
             Text="{Binding ElementName=lstBreaks, Path=SelectedItem.Title, UpdateSourceTrigger=PropertyChanged}"  
             Grid.Row="2" Grid.Column="2"/>
            <ComboBox Name="cbxBreakType" DockPanel.Dock="Bottom" 
              Text="{Binding ElementName=lstBreaks, Path=SelectedItem.Description, UpdateSourceTrigger=PropertyChanged}"  
              Grid.Row="2" Grid.Column="3"/>
        </StackPanel>

    </Grid>


</Window>

Код позади:

using System;
using System.Data;
using System.Windows;
using System.Windows.Controls;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            CreateData();
            this.DataContext = Data;
        }


    public DataSet Data { get; set; }

    private void CreateData()
    {
        Data = new DataSet();
        Data.Tables.Add(CreateJobTable());
        Data.Tables.Add(CreateSessionsTable());
        Data.Tables.Add(CreateBreaks());

        DataRelation relation = GetJobSessionRelations();
        DataRelation relation2 = GetSessionBreakRelations();

        Data.Relations.AddRange(new[] {relation, relation2});
    }

    private DataTable CreateJobTable()
    {
        var jobs = new DataTable();
        jobs.TableName = "JobDetails";
        var col1 = new DataColumn("ID");
        var col2 = new DataColumn("Title");
        var col3 = new DataColumn("Description");

        col1.DataType = Type.GetType("System.Int32");
        col2.DataType = Type.GetType("System.String");
        col3.DataType = Type.GetType("System.String");

        jobs.Columns.Add(col1);
        jobs.Columns.Add(col2);
        jobs.Columns.Add(col3);

        DataRow row = jobs.NewRow();
        row["ID"] = 1;
        row["Title"] = "Job 1";
        row["Description"] = "Job Desc 1";
        jobs.Rows.Add(row);

        DataRow row2 = jobs.NewRow();
        row2["ID"] = 2;
        row2["Title"] = "Job 2";
        row2["Description"] = "Job Desc 2";
        jobs.Rows.Add(row2);

        return jobs;
    }

    private DataTable CreateSessionsTable()
    {
        var sessions = new DataTable();
        sessions.TableName = "SessionDetails";
        var col1 = new DataColumn("ID");
        var col2 = new DataColumn("Title");
        var col3 = new DataColumn("Description");
        var col4 = new DataColumn("JobID");

        col1.DataType = Type.GetType("System.Int32");
        col2.DataType = Type.GetType("System.String");
        col3.DataType = Type.GetType("System.String");
        col4.DataType = Type.GetType("System.Int32");

        sessions.Columns.Add(col1);
        sessions.Columns.Add(col2);
        sessions.Columns.Add(col3);
        sessions.Columns.Add(col4);

        DataRow row = sessions.NewRow();
        row["ID"] = 1;
        row["Title"] = "Session 1";
        row["Description"] = "Session Desc 1";
        row["JobID"] = 1;
        sessions.Rows.Add(row);

        DataRow row2 = sessions.NewRow();
        row2["ID"] = 2;
        row2["Title"] = "Session 2";
        row2["Description"] = "Session Desc 2";
        row2["JobID"] = 1;
        sessions.Rows.Add(row2);

        DataRow row3 = sessions.NewRow();
        row3["ID"] = 3;
        row3["Title"] = "Session 3";
        row3["Description"] = "Session Desc 3";
        row3["JobID"] = 2;
        sessions.Rows.Add(row3);

        DataRow row4 = sessions.NewRow();
        row4["ID"] = 4;
        row4["Title"] = "Session 4";
        row4["Description"] = "Session Desc 4";
        row4["JobID"] = 2;
        sessions.Rows.Add(row4);

        return sessions;
    }

    private DataTable CreateBreaks()
    {
        var breaks = new DataTable();
        breaks.TableName = "BreakDetails";
        var col1 = new DataColumn("ID");
        var col2 = new DataColumn("Title");
        var col3 = new DataColumn("Description");
        var col4 = new DataColumn("SessionID");

        col1.DataType = Type.GetType("System.Int32");
        col2.DataType = Type.GetType("System.String");
        col3.DataType = Type.GetType("System.String");
        col4.DataType = Type.GetType("System.Int32");

        breaks.Columns.Add(col1);
        breaks.Columns.Add(col2);
        breaks.Columns.Add(col3);
        breaks.Columns.Add(col4);

        DataRow row = breaks.NewRow();
        row["ID"] = 1;
        row["Title"] = "Break 1";
        row["Description"] = "Break Desc 1";
        row["SessionID"] = 1;
        breaks.Rows.Add(row);

        DataRow row2 = breaks.NewRow();
        row2["ID"] = 2;
        row2["Title"] = "Break 2";
        row2["Description"] = "Break Desc 2";
        row2["SessionID"] = 2;
        breaks.Rows.Add(row2);

        DataRow row3 = breaks.NewRow();
        row3["ID"] = 3;
        row3["Title"] = "Break 3";
        row3["Description"] = "Break Desc 3";
        row3["SessionID"] = 3;
        breaks.Rows.Add(row3);


        DataRow row4 = breaks.NewRow();
        row4["ID"] = 4;
        row4["Title"] = "Break 4";
        row4["Description"] = "Break Desc 4";
        row4["SessionID"] = 4;
        breaks.Rows.Add(row4);

        return breaks;
    }

    private DataRelation GetSessionBreakRelations()
    {
        return new DataRelation("relJobDetailsSessionDetails", Data.Tables["JobDetails"].Columns["ID"],
                                Data.Tables["SessionDetails"].Columns["JobID"]);
    }

    private DataRelation GetJobSessionRelations()
    {
        var dataRelation = new DataRelation("relSessionDetailsBreakDetails", Data.Tables["SessionDetails"].Columns["ID"],
                                            Data.Tables["BreakDetails"].Columns["SessionID"]);
        return dataRelation;
    }

    private void lstJobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

    }

    private void lstSessions_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

    }

    private void lstBreaks_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {

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