WPF 按钮位于数据上下文之外,无法绑定

发布于 2024-09-18 08:39:05 字数 5705 浏览 7 评论 0 原文

alt text您好,

我的 有 3 个按钮添加、删除、打开为 RelayCommands >文档视图模型。 下面你可以看到我是如何绑定它们的。当然,这些绑定不起作用,因为数据设置为 ListBoxItemsSource,而按钮位于该列表的外部...

然后我尝试的是在您在代码片段中看到的第一个 StackPanel 处设置 DataContext。

像这样:

但随后出现了一个新问题...现在文档在 ListBox 中不再可见/列出:/

< em>我怎样才能让两者都工作?

<StackPanel Orientation="Vertical" >
                                            <ListBox 
                                                Height="100"
                                                Width="Auto"
                                                Focusable="True"
                                                ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                                                ScrollViewer.VerticalScrollBarVisibility="Auto" 
                                                Grid.Row="1" 
                                                Name="itemListBox"
                                                BorderThickness="1"      
                                                ItemsSource="{Binding DocumentViewModelList}"
                                                >
                                                <ListBox.ItemTemplate>
                                                    <DataTemplate>
                                                        <StackPanel>      
                                                            <!-- xxx -->
                                                            <TextBlock Text="{Binding Path=Name}" />
                                                        </StackPanel>
                                                    </DataTemplate>
                                                </ListBox.ItemTemplate>
                                                <ListBox.ItemContainerStyle>                                                  
                                                        <Style TargetType="{x:Type ListBoxItem}">
                                                            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
                                                        </Style>                                                  
                                                </ListBox.ItemContainerStyle>
                                            </ListBox>
                                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">                                                
                                                <Button Command="{Binding DeleteDocumentCommand}" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Content="Delete" />
                                                <Button Command="{Binding    AddDocumentCommand}" HorizontalAlignment="Stretch" Content="Add" />
                                                <Button Command="{Binding   OpenDocumentCommand}" HorizontalAlignment="Stretch" Content="Open" />                                               
                                            </StackPanel>
                                        </StackPanel>

更新

我尝试了这个

 <Button Command="{Binding Path=DeleteDocumentCommand, RelativeSource={RelativeSource AncestorType={x:Type DocumentViewModel}}}"

并得到了这个:类型引用找不到名为“DocumentViewModel”的公共类型

我想坚持使用 StackPanel DataContext 解决方案,并以某种方式使 ListBox.ItemsSource 通过与 FindAncestor 的relativeSource 绑定来抓取 DocumentViewModelList。我尝试了一些东西,但没有运气,也许有人可以发布一个不错的片段:)

好吧,我找到了解决方案:

这绑定到当前的 DataContext,即“DocumentViewModelList”,酷!

更新2:

好吧,还有另一个问题,也许如果有人可以提供解决方案,那么我会将此线程标记为解决方案。不想打开一个新线程,因为整个文本+代码片段是相同的...现在的问题是=>选择第一个文档激活按钮。选择任何其他按钮不会激活按钮,为什么?我的 IsSelected 属性的绑定有什么问题?

DocumentViewModel.cs:

private bool _isSelected;
        public bool IsSelected 
        {
            get { return _isSelected; }
            set
            {
                if (_isSelected == value)
                    return;

                _isSelected = value;
                this.RaisePropertyChanged("IsSelected");
            }
        }  

更新2:

这是启用按钮的代码:我做错了什么?我在输出控制台中没有收到任何绑定错误!?

private void DeleteDocument()
        {
            throw new NotImplementedException();
        }

        private bool CanDeleteDocument()
        {
            return (IsSelected == true);
        }

        private void AddDocument()
        { 

        }

        private void OpenDocument()
        { 

        }

        public RelayCommand DeleteDocumentCommand
        {
            get { return _deleteDocumentCommand ?? (_deleteDocumentCommand = new RelayCommand(() => DeleteDocument(), () => CanDeleteDocument())); }
        }

        public RelayCommand AddDocumentCommand
        {
            get { return _addDocumentCommand ?? (_addDocumentCommand = new RelayCommand(() => AddDocument())); }
        }

        public RelayCommand OpenDocumentCommand
        {
            get { return _openDocumentCommand ?? (_openDocumentCommand = new RelayCommand(() => OpenDocument())); }
        }

alt textHello,

I have 3 Buttons add,delete,open as RelayCommands in my DocumentViewModel.
Below you see how I have bound them. Of course those binding does not work, because the data is set to the ItemsSource of the ListBox and the buttons are outside of that...

What I tried then is to set the DataContext at the first StackPanel you see in my code snippet.

like this: <StackPanel DataContext="{Binding DocumentViewModelList}" >

BUT then a new problem arised... now the documents are NOT visible/listed anymore in the ListBox :/

How can I make BOTH working?

<StackPanel Orientation="Vertical" >
                                            <ListBox 
                                                Height="100"
                                                Width="Auto"
                                                Focusable="True"
                                                ScrollViewer.HorizontalScrollBarVisibility="Auto" 
                                                ScrollViewer.VerticalScrollBarVisibility="Auto" 
                                                Grid.Row="1" 
                                                Name="itemListBox"
                                                BorderThickness="1"      
                                                ItemsSource="{Binding DocumentViewModelList}"
                                                >
                                                <ListBox.ItemTemplate>
                                                    <DataTemplate>
                                                        <StackPanel>      
                                                            <!-- xxx -->
                                                            <TextBlock Text="{Binding Path=Name}" />
                                                        </StackPanel>
                                                    </DataTemplate>
                                                </ListBox.ItemTemplate>
                                                <ListBox.ItemContainerStyle>                                                  
                                                        <Style TargetType="{x:Type ListBoxItem}">
                                                            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
                                                        </Style>                                                  
                                                </ListBox.ItemContainerStyle>
                                            </ListBox>
                                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">                                                
                                                <Button Command="{Binding DeleteDocumentCommand}" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Content="Delete" />
                                                <Button Command="{Binding    AddDocumentCommand}" HorizontalAlignment="Stretch" Content="Add" />
                                                <Button Command="{Binding   OpenDocumentCommand}" HorizontalAlignment="Stretch" Content="Open" />                                               
                                            </StackPanel>
                                        </StackPanel>

UPDATE:

I tried this:

 <Button Command="{Binding Path=DeleteDocumentCommand, RelativeSource={RelativeSource AncestorType={x:Type DocumentViewModel}}}"

and got this: The type reference cannot find a public type named 'DocumentViewModel'

I would like to stick with the StackPanel DataContext solution and make somehow the ListBox.ItemsSource grabbing the DocumentViewModelList via RelativeSource binding with FindAncestor. I tried some things but no luck, maybe someone can post a nice snippet :)

OK I found the solution: <ListBox ItemsSource="{Binding}" ...

this is binding to the current DataContext that is "DocumentViewModelList" cool!

UPDATE 2:

ok there is still another problem, maybe if someone can provide a solution on this I mark this thread as a solution then. Do not want to open a new thread, because the whole text+code snippet is the same... Problem now is =>Selecting The 1st Document activates the Button. Selecting any other Button does not activate a Button, WHY? What is wrong with the binding of my IsSelected property ?

DocumentViewModel.cs:

private bool _isSelected;
        public bool IsSelected 
        {
            get { return _isSelected; }
            set
            {
                if (_isSelected == value)
                    return;

                _isSelected = value;
                this.RaisePropertyChanged("IsSelected");
            }
        }  

UPDATE 2:

This is the code for enabling the buttons: What do I wrong? I get no binding errors in the output console!?

private void DeleteDocument()
        {
            throw new NotImplementedException();
        }

        private bool CanDeleteDocument()
        {
            return (IsSelected == true);
        }

        private void AddDocument()
        { 

        }

        private void OpenDocument()
        { 

        }

        public RelayCommand DeleteDocumentCommand
        {
            get { return _deleteDocumentCommand ?? (_deleteDocumentCommand = new RelayCommand(() => DeleteDocument(), () => CanDeleteDocument())); }
        }

        public RelayCommand AddDocumentCommand
        {
            get { return _addDocumentCommand ?? (_addDocumentCommand = new RelayCommand(() => AddDocument())); }
        }

        public RelayCommand OpenDocumentCommand
        {
            get { return _openDocumentCommand ?? (_openDocumentCommand = new RelayCommand(() => OpenDocument())); }
        }

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

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

发布评论

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

评论(1

遗失的美好 2024-09-25 08:39:05

DocumentViewModelList 是您的 DocumentViewModel 的属性吗?

通常,我会拥有该窗口的 ViewModel,它将公开 ObservableCollection,其中 T 是您想要在列表中显示的内容。然后,您可以将Window/Page等的DataContext分配给ViewModel,然后将ListBoxItemsSource绑定到它ObservableCollection 属性。

例如,这是我的 ViewModel 的片段。

public class SomeViewModel
{
  public ObservableCollection<SingleDocumentViewModel> Docs {get; private set; }

  // other properties can go here
}

在 XAML 的代码隐藏中(我通常在构造函数中执行此操作),您可以将其 DataContext 设置为 ViewModel 的新实例。

public AwesomeDocumentList()
{
  this.DataContext = new SomeViewModel();
  // the rest of the constructor
}

设置窗口的 DataContext 后,您可以绑定 ItemsSource 到公开的属性(我称之为Docs

<ListBox ItemsSource="{Binding Docs}" ... />

希望有帮助。

更新

在按钮的 RelayCommand 中,您是否为 CanExecute 谓词指定了某些内容?如果没有,那么我相信 RelayCommand 将默认为始终启用。但如果您指定了谓词,请查看其中。

您为 IsSelected 属性发布的代码看起来不错。看起来问题出在其他地方。

Is the DocumentViewModelList a property of your DocumentViewModel?

Typically, what I would have is a ViewModel for that window which would expose an ObservableCollection<T> where T is what you want displayed in the list. Then, you can assign the Window/Page/etc.'s DataContext to the ViewModel, and then bind the ItemsSource of the ListBox to that ObservableCollection<T> property.

For example, here would be a snippet of my ViewModel.

public class SomeViewModel
{
  public ObservableCollection<SingleDocumentViewModel> Docs {get; private set; }

  // other properties can go here
}

In the code-behind for the XAML, (I usually do it in the constructor), you can set its DataContext to a new instance of your ViewModel

public AwesomeDocumentList()
{
  this.DataContext = new SomeViewModel();
  // the rest of the constructor
}

With the Window's DataContext set, you can bind the ItemsSource to the exposed property (I called it Docs)

<ListBox ItemsSource="{Binding Docs}" ... />

Hope that helps.

Update

In the RelayCommand for the button, do you have something specified for the CanExecute predicate? If not, then I believe the RelayCommand will default to always enabled. But if you have a predicate specified, take a look in there.

The code you posted for the IsSelected property looks fine. Looks like the problem lies elsewhere.

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