WPF 数据模板

发布于 2024-08-29 17:39:43 字数 1936 浏览 4 评论 0原文

我正在开始使用 WPF,并尝试将数据连接到 UI。我已经成功地连接到一个类,没有任何问题,但我真正想做的是连接到主窗口的属性。

这是 XAML:

<Window x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <CollectionViewSource
        Source="{Binding Source={x:Static Application.Current}, Path=Platforms}"
        x:Key="platforms"/>
    <DataTemplate DataType="{x:Type custom:Platform}">
        <StackPanel>
            <CheckBox IsChecked="{Binding Path=Selected}"/>
            <TextBlock Text="{Binding Path=Name}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Source={StaticResource platforms}}"/>
</Grid>

这是主窗口的代码:

public partial class MainWindow : Window
{
    ObservableCollection<Platform> m_platforms;

    public MainWindow()
    {
        m_platforms = new ObservableCollection<Platform>();

        m_platforms.Add(new Platform("PC"));

        InitializeComponent();
    }

    public ObservableCollection<Platform> Platforms
    {
        get { return m_platforms; }
        set { m_platforms = value; }
    }
}

这是 Platform 类:

public class Platform
{
    private string m_name;
    private bool m_selected;

    public Platform(string name)
    {
        m_name = name;
        m_selected = false;
    }

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public bool Selected
    {
        get { return m_selected; }
        set { m_selected = value; }
    }
}

这一切都编译并运行良好,但列表框显示没有任何内容。如果我在 Platforms 的 get 方法上放置断点,则不会调用它。我不明白 XAML 应该连接到平台!

I'm getting started with WPF and trying to get my head around connecting data to the UI. I've managed to connect to a class without any issues, but what I really want to do is connect to a property of the main window.

Here's the XAML:

<Window x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <CollectionViewSource
        Source="{Binding Source={x:Static Application.Current}, Path=Platforms}"
        x:Key="platforms"/>
    <DataTemplate DataType="{x:Type custom:Platform}">
        <StackPanel>
            <CheckBox IsChecked="{Binding Path=Selected}"/>
            <TextBlock Text="{Binding Path=Name}"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Source={StaticResource platforms}}"/>
</Grid>

Here's the code for the main window:

public partial class MainWindow : Window
{
    ObservableCollection<Platform> m_platforms;

    public MainWindow()
    {
        m_platforms = new ObservableCollection<Platform>();

        m_platforms.Add(new Platform("PC"));

        InitializeComponent();
    }

    public ObservableCollection<Platform> Platforms
    {
        get { return m_platforms; }
        set { m_platforms = value; }
    }
}

Here's the Platform class:

public class Platform
{
    private string m_name;
    private bool m_selected;

    public Platform(string name)
    {
        m_name = name;
        m_selected = false;
    }

    public string Name
    {
        get { return m_name; }
        set { m_name = value; }
    }

    public bool Selected
    {
        get { return m_selected; }
        set { m_selected = value; }
    }
}

This all compiles and runs fine but the list box displays with nothing in it. If I put a breakpoint on the get method of Platforms, it doesn't get called. I don't understand as Platforms is what the XAML should be connecting to!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

鹿港巷口少年归 2024-09-05 17:39:43

除了 CollectionViewSource 上的 Source 上的 Binding 不正确之外,您的代码看起来不错。您的意思可能是这样的:

 <CollectionViewSource
    Source="{Binding Source={x:Static Application.Current}, Path=MainWindow.Platforms}"
    x:Key="platforms"/>

如果没有此更改,绑定实际上会在 Application 实例上查找属性 Platforms

Your code looks ok apart from the fact that the Binding on Source on CollectionViewSource is not correct. You probably meant this:

 <CollectionViewSource
    Source="{Binding Source={x:Static Application.Current}, Path=MainWindow.Platforms}"
    x:Key="platforms"/>

Without this change the Binding actually looked for property Platforms on Application instance.

送君千里 2024-09-05 17:39:43

我建议您不要将平台添加到 MainWindow 中,而是将其设置为 MainWindow 的 DataContext(包装在 ViewModel 内)。

这样您就可以非常轻松地对其进行绑定(绑定代码类似于 ItemsSource={Binding Path=Platforms})。

这是 WPF 设计的一部分,每个表单都应该有一个与之绑定的显式 DataContext。

I would suggest you add the platforms not to the MainWindow but rather set it as the MainWindow's DataContext (wrapped inside a ViewModel).

That way you can very easily bind against it (the binding code would look like ItemsSource={Binding Path=Platforms}).

This is part of WPFs design, that every form should have a explicit DataContext it binds to.

极致的悲 2024-09-05 17:39:43

一个更合适的解决方案是给你的窗口命名。一个不错的约定是 _this。

<Window x:Name="_this" x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding ElementName=_this, Path=Platforms}"
            x:Key="platforms"/>
        <DataTemplate DataType="{x:Type custom:Platform}">
            <StackPanel>
                <CheckBox IsChecked="{Binding Path=Selected}"/>
                <TextBlock Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource platforms}}"/>
    </Grid>

A somewhat more appropriate solution is to give your window a name. A nice convention is _this.

<Window x:Name="_this" x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding ElementName=_this, Path=Platforms}"
            x:Key="platforms"/>
        <DataTemplate DataType="{x:Type custom:Platform}">
            <StackPanel>
                <CheckBox IsChecked="{Binding Path=Selected}"/>
                <TextBlock Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Source={StaticResource platforms}}"/>
    </Grid>
烟燃烟灭 2024-09-05 17:39:43

这是我更新的代码,XAML:

<Window x:Name="_this"
    x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="190" Width="177">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding ElementName=_this, Path=Platforms}"
            x:Key="platforms"/>
        <DataTemplate x:Key="platformTemplate" DataType="{x:Type custom:Platform}">
            <StackPanel Orientation="Horizontal">
                <CheckBox Margin="1" IsChecked="{Binding Path=Selected}"/>
                <TextBlock Margin="1" Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="23" />
            <RowDefinition Height="23" />
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0"
            ItemsSource="{Binding Source={StaticResource platforms}}" 
            ItemTemplate="{StaticResource platformTemplate}"/>
        <Button Click="OnBuild" Grid.Row="1">Build...</Button>
        <Button Click="OnTogglePC" Grid.Row="2">Toggle PC</Button>
    </Grid>
</Window>

XAML 背后的代码:

public partial class MainWindow : Window
{
    ObservableCollection<Platform> m_platforms;

    public MainWindow()
    {
        m_platforms = new ObservableCollection<Platform>();

        m_platforms.Add(new Platform("PC"));
        m_platforms.Add(new Platform("PS3"));
        m_platforms.Add(new Platform("Xbox 360"));

        InitializeComponent();
    }

    public ObservableCollection<Platform> Platforms
    {
        get { return m_platforms; }
        set { m_platforms = value; }
    }

    private void OnBuild(object sender, RoutedEventArgs e)
    {
        string text = "";

        foreach (Platform platform in m_platforms)
        {
            if (platform.Selected)
            {
                text += platform.Name + " ";
            }
        }

        if (text == "")
        {
            text = "none";
        }

        MessageBox.Show(text, "WPF TEST");
    }

    private void OnTogglePC(object sender, RoutedEventArgs e)
    {
        m_platforms[0].Selected = !m_platforms[0].Selected;
    }
}

...最后是平台代码,经过增强以完成双向交互:

public class Platform : INotifyPropertyChanged
{
    private string m_name;
    private bool m_selected;

    public Platform(string name)
    {
        m_name = name;
        m_selected = false;
    }

    public string Name
    {
        get { return m_name; }
        set
        {
            m_name = value;

            OnPropertyChanged("Name");
        }
    }

    public bool Selected
    {
        get { return m_selected; }
        set
        {
            m_selected = value;

            OnPropertyChanged("Selected");
        }
    }

    private void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Here's my updated code, the XAML:

<Window x:Name="_this"
    x:Class="test3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test3"
    Title="MainWindow" Height="190" Width="177">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding ElementName=_this, Path=Platforms}"
            x:Key="platforms"/>
        <DataTemplate x:Key="platformTemplate" DataType="{x:Type custom:Platform}">
            <StackPanel Orientation="Horizontal">
                <CheckBox Margin="1" IsChecked="{Binding Path=Selected}"/>
                <TextBlock Margin="1" Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="23" />
            <RowDefinition Height="23" />
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0"
            ItemsSource="{Binding Source={StaticResource platforms}}" 
            ItemTemplate="{StaticResource platformTemplate}"/>
        <Button Click="OnBuild" Grid.Row="1">Build...</Button>
        <Button Click="OnTogglePC" Grid.Row="2">Toggle PC</Button>
    </Grid>
</Window>

The code behind the XAML:

public partial class MainWindow : Window
{
    ObservableCollection<Platform> m_platforms;

    public MainWindow()
    {
        m_platforms = new ObservableCollection<Platform>();

        m_platforms.Add(new Platform("PC"));
        m_platforms.Add(new Platform("PS3"));
        m_platforms.Add(new Platform("Xbox 360"));

        InitializeComponent();
    }

    public ObservableCollection<Platform> Platforms
    {
        get { return m_platforms; }
        set { m_platforms = value; }
    }

    private void OnBuild(object sender, RoutedEventArgs e)
    {
        string text = "";

        foreach (Platform platform in m_platforms)
        {
            if (platform.Selected)
            {
                text += platform.Name + " ";
            }
        }

        if (text == "")
        {
            text = "none";
        }

        MessageBox.Show(text, "WPF TEST");
    }

    private void OnTogglePC(object sender, RoutedEventArgs e)
    {
        m_platforms[0].Selected = !m_platforms[0].Selected;
    }
}

...and finally the Platform code, enhanced to finish off the two way interaction:

public class Platform : INotifyPropertyChanged
{
    private string m_name;
    private bool m_selected;

    public Platform(string name)
    {
        m_name = name;
        m_selected = false;
    }

    public string Name
    {
        get { return m_name; }
        set
        {
            m_name = value;

            OnPropertyChanged("Name");
        }
    }

    public bool Selected
    {
        get { return m_selected; }
        set
        {
            m_selected = value;

            OnPropertyChanged("Selected");
        }
    }

    private void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
柠北森屋 2024-09-05 17:39:43

使用 DataContext,一切变得更加容易!

<Window x:Class="test5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test5"
    Title="MainWindow" Height="190" Width="177">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding Path=.}"
            x:Key="platforms"/>
        <DataTemplate x:Key="platformTemplate" DataType="{x:Type custom:Platform}">
            <StackPanel Orientation="Horizontal">
                <CheckBox Margin="1" IsChecked="{Binding Path=Selected}"/>
                <TextBlock Margin="1" Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="23" />
            <RowDefinition Height="23" />
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0"
            ItemsSource="{Binding Source={StaticResource platforms}}" 
            ItemTemplate="{StaticResource platformTemplate}"/>
        <Button Click="OnBuild" Grid.Row="1">Build...</Button>
        <Button Click="OnTogglePC" Grid.Row="2">Toggle PC</Button>
    </Grid>
</Window>

下面是其背后的代码:

private ObservableCollection<Platform> m_platforms;

public MainWindow()
{
    InitializeComponent();

    m_platforms = new ObservableCollection<Platform>();

    m_platforms.Add(new Platform("PC"));
    m_platforms.Add(new Platform("PS3"));
    m_platforms.Add(new Platform("Xbox 360"));

    DataContext = m_platforms;
}

public void OnBuild(object sender, RoutedEventArgs e)
{
    string text = "";

    foreach (Platform platform in m_platforms)
    {
        if (platform.Selected)
        {
            text += platform.Name + " ";
        }
    }

    if (text == "")
    {
        text = "none";
    }

    MessageBox.Show(text, "WPF TEST");
}

public void OnTogglePC(object sender, RoutedEventArgs e)
{
    m_platforms[0].Selected = !m_platforms[0].Selected;
}

请注意,我不再需要将 Platforms 声明为主窗口的属性,而是将其分配给 DataContext,并且 XAML 源变成简单的“.”。

Using DataContext, it gets even easier!

<Window x:Class="test5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:custom="clr-namespace:test5"
    Title="MainWindow" Height="190" Width="177">
    <Window.Resources>
        <CollectionViewSource
            Source="{Binding Path=.}"
            x:Key="platforms"/>
        <DataTemplate x:Key="platformTemplate" DataType="{x:Type custom:Platform}">
            <StackPanel Orientation="Horizontal">
                <CheckBox Margin="1" IsChecked="{Binding Path=Selected}"/>
                <TextBlock Margin="1" Text="{Binding Path=Name}"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="23" />
            <RowDefinition Height="23" />
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0"
            ItemsSource="{Binding Source={StaticResource platforms}}" 
            ItemTemplate="{StaticResource platformTemplate}"/>
        <Button Click="OnBuild" Grid.Row="1">Build...</Button>
        <Button Click="OnTogglePC" Grid.Row="2">Toggle PC</Button>
    </Grid>
</Window>

Here's the code behind this:

private ObservableCollection<Platform> m_platforms;

public MainWindow()
{
    InitializeComponent();

    m_platforms = new ObservableCollection<Platform>();

    m_platforms.Add(new Platform("PC"));
    m_platforms.Add(new Platform("PS3"));
    m_platforms.Add(new Platform("Xbox 360"));

    DataContext = m_platforms;
}

public void OnBuild(object sender, RoutedEventArgs e)
{
    string text = "";

    foreach (Platform platform in m_platforms)
    {
        if (platform.Selected)
        {
            text += platform.Name + " ";
        }
    }

    if (text == "")
    {
        text = "none";
    }

    MessageBox.Show(text, "WPF TEST");
}

public void OnTogglePC(object sender, RoutedEventArgs e)
{
    m_platforms[0].Selected = !m_platforms[0].Selected;
}

Note that I've dropped the need to declare Platforms as a property of the main window, instead I assign it to the DataContext, and the XAML source becomes, simply, "."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文