【问题标题】:Why does binding of my ObservableCollection<string> to Listbox not work?为什么我的 ObservableCollection<string> 绑定到 Listbox 不起作用?
【发布时间】:2014-12-26 16:54:51
【问题描述】:

当我更新 ObservableCollection&lt;string&gt; 并调用 RaisePropertyChanged(..) 时,它的内容不会显示在 WPF 中的 Listbox 中。我不知道我做错了什么。

关键部分是我更新 FileNames 属性的地方:

public class HistoricalDataViewRawDataViewModel : ViewModelBase
{
    private string _currentDirectory;
    private ObservableCollection<string> _fileNames;
    private List<string> _rawData;

    public ICommand ChangeDirectoryCommand { get; private set; }
    public string CurrentDirectory
    {
        get { return _currentDirectory; }
        set
        {
            if (_currentDirectory != value)
            {
                _currentDirectory = value;
                RaisePropertyChanged("CurrentDirectory");
            }
        }
    }
    public ObservableCollection<string> FileNames
    {
        get { return _fileNames; }
        set
        {
            if (_fileNames != value)
            {
                _fileNames = value;
                RaisePropertyChanged("FileNames");
            }
        }
    }

    public List<string> RawData
    {
        get { return _rawData; }
        set
        {
            if (_rawData != value)
            {
                _rawData = value;
                RaisePropertyChanged("RawData");
            }
        }
    }

    public HistoricalDataViewRawDataViewModel()
    {
        ChangeDirectoryCommand = new RelayCommand(ChangeDirectory);
        var fileDirectory = Properties.Settings.Default.HistoricalData_RawDataSourceDirectory;

        //set current directory
        CurrentDirectory = fileDirectory;

        //load all fileNames
        LoadAvailableFileNames(fileDirectory);
    }

    private void ChangeDirectory()
    {
        using (var folderDialog = new FolderBrowserDialog())
        {
            folderDialog.SelectedPath = CurrentDirectory;
            folderDialog.ShowDialog();

            //set current directory
            CurrentDirectory = folderDialog.SelectedPath;

            //save current directory to settings
            Properties.Settings.Default.HistoricalData_RawDataSourceDirectory = CurrentDirectory;
            Properties.Settings.Default.Save();

            //load files in chosen directory
            LoadAvailableFileNames(CurrentDirectory);
        }
    }

    private void LoadAvailableFileNames(string directory)
    {
        FileNames = new ObservableCollection<string>(FileIO.GetFileNamesInDirectory(directory, false, true));
    }
    private async void LoadRawData(string fileName)
    {

    }}

这是 xaml 代码。它应该按原样工作,因为我希望显示ObservableCollection&lt;string&gt;。我从代码隐藏添加了几个项目到列表框中,它显示得很好:

DataContext="{Binding HistoricalDataViewRawDataViewModel, Source={StaticResource Locator}}">

<Grid>

    <Grid.RowDefinitions>
        <RowDefinition Height="50" />
        <RowDefinition />
    </Grid.RowDefinitions>

    <StackPanel Grid.Row="0" Orientation="Horizontal">
        <ToggleButton Margin="10"  HorizontalAlignment="Left" VerticalAlignment="Center" Content="Choose Directory" FontSize="18" Foreground="White" Command="{Binding ChangeDirectoryCommand}"/>
        <TextBlock 
            Margin="10"
            FontSize="18"
            Foreground="White"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            TextAlignment="Center"
            Text="{Binding CurrentDirectory}"/>
    </StackPanel>

    <dxdo:DockLayoutManager Grid.Row="1">

        <dxdo:LayoutGroup Orientation="Vertical">

            <dxdo:LayoutPanel ItemHeight="7*">
                <dxdo:LayoutControlItem>
                    <ListBox Name="MyListBox" ItemsSource="{Binding FileNames}"/>
                </dxdo:LayoutControlItem>
            </dxdo:LayoutPanel>

            <dxdo:LayoutPanel Caption="Activity Log" ItemHeight="200" >
                <dxdo:LayoutControlItem>
                    <ListBox/>
                </dxdo:LayoutControlItem>
            </dxdo:LayoutPanel>

        </dxdo:LayoutGroup>

    </dxdo:DockLayoutManager>

</Grid>

【问题讨论】:

  • @GrantWinney,为什么会这样?我什至不绑定RawData。但我是为了好玩才改的,没改。
  • 列表? FileNames 是 ObservableCollection 而不是 List。我假设您的 DataContext 设置不正确,这会破坏您在 ItemsSource="{Binding FileNames} 中的绑定。您能显示您设置数据上下文的位置吗?
  • @user1182735,datacontext 设置正确,我在我的视图模型中看到了对FileNames 的引用。但我也添加了 xaml 代码行
  • @GrantWinney,公平评论,我关心FileNames。我编辑了我的问题以使其更清楚。
  • 我可以建议您创建一个minimal example 吗?显然,RawData 和条目是文件名这一事实都与问题的核心无关。并且对某些 dxdo: 命名空间的依赖会阻止其他人尝试重现您的问题。

标签: c# wpf mvvm listbox mvvm-light


【解决方案1】:

根据 DevExpress 中的this support ticket,只需删除LayoutControlItem 即可。

我使用您的 XAML 和一些虚拟数据创建了一个示例项目,它工作正常:

<Window x:Class="WpfApplication12.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dxdo="http://schemas.devexpress.com/winfx/2008/xaml/docking"
        Title="MainWindow" Height="350" Width="525">
    <dxdo:DockLayoutManager Grid.Row="1">

        <dxdo:LayoutGroup Orientation="Vertical">

            <dxdo:LayoutPanel ItemHeight="7*">
                <!-- notice the removal of LayoutControlItem here -->
                <ListBox ItemsSource="{Binding FileNames}"/>
            </dxdo:LayoutPanel>

            <dxdo:LayoutPanel Caption="Activity Log" ItemHeight="200" >
                <ListBox/>
            </dxdo:LayoutPanel>
        </dxdo:LayoutGroup>
    </dxdo:DockLayoutManager>
</Window>

代码背后:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        //Dummy data
        DataContext = new
        {
            FileNames = Enumerable.Range(0, 5).Select(x => "File" + x.ToString())
        };
    }
}

结果:

【讨论】:

  • 附带说明:在使用 WPF 时,您需要 Snoop 就像水一样(至少在 VS 2015 发布之前具有类似的功能)。
  • 附注 2:您的 ObservableCollections 应该是只读属性 ({get {....}}),并且仅在 VM 构造函数中实例化一次。这样可以减少一点代码并保证您始终绑定正确的集合。
  • 太棒了,成功了。实际上,我将字符串集合更改为List&lt;string&gt;,因为我从不更改集合中的单个元素,每次绑定一个全新的集合时[我听从您的建议,而是清除现有列表并通过AddRange 添加。
【解决方案2】:

我认为这些 dxdo 控件是非标准控件?我假设这些控件破坏了继承机制。继承机制适用于所有 FrameworkElement 对象。这意味着属性值沿逻辑树继承。这使您可以在外部 Grid 上设置 datacontext 属性,但可以在例如 TextBlock 上使用它。您在 Grid 上设置的值由 StackPanel 继承,然后由 TextBlock 继承。这仅适用于从 FrameworkElement 继承的对象。

可以直接在ListBox上设置datacontext吗? .如果这有效,则表明禁止上下文已损坏。

【讨论】:

  • 它可以工作,但是如果textblocktextblockbutton 的相同数据上下文上方的几行工作正常,那么数据上下文怎么会被破坏?
  • DataContext 值的继承沿逻辑树工作。 Textblock 是 StackPanel 的孩子,它是 Grid 的孩子,它是任何孩子的孩子。这些都是FrameworkElements,这意味着它们支持继承机制。您的 ListBox 是 LayoutControlItem 的子级,它是 LayoutPanel 的子级,LayoutGroup 的子级是 DockLayoutManager 的子级。我不知道这些 DevEx 元素是否支持属性继承。看起来他们没有。
  • 啊,现在更有意义了。谢谢,我会检查一下,如果我能识别出没有正确继承的数据上下文,也许我可以在“链”中声明更高的数据上下文。
  • 您还可以使用其他解决方法:codeproject.com/Articles/27432/…。这是高级wpf。祝你好运!
  • 感谢您的帮助。 DX LayoutControlItem 似乎引起了问题。
猜你喜欢
  • 2018-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-17
  • 2012-02-29
  • 2011-03-17
相关资源
最近更新 更多