WPF将ObservableCollection绑定到UserControl的意外行为

时间:2015-09-16 15:24:25

标签: c# wpf xaml data-binding

我试图将一堆用户控件绑定到WPF应用程序。想法是viewmodel保存服务器名称列表,将它们传递给ObservableCollection,然后集合绑定到主窗口。

在设计模式下,一切正常!但是,当我运行应用程序时,绑定似乎崩溃了,我无法解释原因。

enter image description here

这是用户控件的XAML:

<UserControl x:Class="ServerMonitor.Wpf.ServerControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ServerMonitor.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.DataContext>
        <local:Server />
    </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Grid.Resources>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="TextAlignment" Value="Center" />
                <Setter Property="HorizontalAlignment" Value="Stretch" />
            </Style>
        </Grid.Resources>

        <TextBlock Grid.Row="0" Text="{Binding Name}" />

        <TextBlock Grid.Row="8" Text="{Binding LastPolled}" />
    </Grid>
</UserControl>

这是视图模型(ViewModelBase是一个实现INotifyPropertyChanged的抽象类):

public class MainWindowViewModel : ViewModelBase {

    private List<string> _MachineNames = new List<string> {
        "wschampad",
        // Test
        "T009", "T010", "T011", "T012",
    };
    public List<string> MachineNames {
        get { return _MachineNames; }
        set { _MachineNames = value; OnPropertyChanged("ManchineNames"); }
    }

    private ObservableCollection<Server> _Servers;
    public ObservableCollection<Server> Servers {
        get {
            if (_Servers == null) {
                _Servers = new ObservableCollection<Server>();
                foreach (var machine in MachineNames) {
                    _Servers.Add(new Server {
                        Name = machine, 
                        LastPolled = DateTime.Now, 
                    });
                }
                OnPropertyChanged("Servers");
            }

            return _Servers;
        }
        set { _Servers = value; OnPropertyChanged("Servers"); }
    }
}

这是主窗口XAML:

<Window x:Class="ServerMonitor.Wpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ServerMonitor.Wpf"
        Title="Leading Hedge Server Monitor" Height="350" Width="800">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <Menu Grid.Row="0">
            <MenuItem Header="_File">
                <MenuItem Header="_Exit" Name="MenuFileExit" Click="MenuFileExit_Click" />

            </MenuItem>
            <MenuItem Header="_Edit">
                <MenuItem Header="_Options" Name="MenuEditOptions" IsEnabled="False" />
            </MenuItem>
            <MenuItem Header="_Help">
                <MenuItem Header="_About" Name="MenuHelpAbout" IsEnabled="False" />
            </MenuItem>
        </Menu>

        <ItemsControl Grid.Row="1" ItemsSource="{Binding Servers}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="1" Margin="5,5,5,5">
                        <local:ServerControl DataContext="{Binding}" />
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

    </Grid>
</Window>

修改

将UserControl中的DataContext更改为可忽略的工作以解决问题!

<UserControl x:Class="ServerMonitor.Wpf.ServerControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ServerMonitor.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <d:UserControl.DataContext>
        <local:Server />
    </d:UserControl.DataContext>

1 个答案:

答案 0 :(得分:3)

在UserControl中删除它:

<UserControl.DataContext>
    <local:Server />
</UserControl.DataContext>

这会覆盖DataContext您从ItemTemplate传递给它的DateTime,最终会得到stringCommand.Parameters的默认值。