Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/334.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 与Notifyi的WPF绑定不会更新UI_C#_Wpf_Xaml_Mvvm_Inotifypropertychanged - Fatal编程技术网

C# 与Notifyi的WPF绑定不会更新UI

C# 与Notifyi的WPF绑定不会更新UI,c#,wpf,xaml,mvvm,inotifypropertychanged,C#,Wpf,Xaml,Mvvm,Inotifypropertychanged,我的问题是,即使触发PropertyChanged,UI也不会更新。 XAML: 和数据上下文: await System.Windows.Application.Current.Dispatcher.BeginInvoke( DispatcherPriority.Background, new Action( () => this.BookShelf.DataContext = bookShelfViewModel )

我的问题是,即使触发PropertyChanged,UI也不会更新。 XAML:

和数据上下文:

await System.Windows.Application.Current.Dispatcher.BeginInvoke(
         DispatcherPriority.Background, new Action(
                () => this.BookShelf.DataContext = bookShelfViewModel
         )
       );
我对这种MVVM设计非常陌生,从我读过的文章中可以看出,我找不到哪里出了问题。我猜使用Dispatcher是没有必要的,但我认为在这种情况下它并不重要。。。 ListBox确实显示了我的对象,但这里的问题是更新SelectedItem

更新:

以下是我的DbInfo代码:

public class DbInfo
{
    public int RelatedId { get; set; }
    public string DbId { get; set; }
    public TBase3.Article currentArticle { get; set; }
    public string LinkId { get; set; }
    public bool IsArticle { get; set; }
    public string folder { get; set; }
    public bool IsNamedArticle { get; set; }
    public int currentBlockIndex { get; set; }
    public int currentBlockCount { get; set; }
    public string DisplayName { get; set; }
    public int VScrollPos { get; set; }
    public int THTextVersion { get; set; }
    public bool isHtmlToc { get; set; }
    public ImageSource bookImage { get; set; }
}
提醒我,当我为ViewModel->SelectedItem设置新值时,它会转到PropertyChanged(这个,e);线路。它没有选择在列表框中选择的DbInfo

更新2:

我在窗口的右边看到了一张书单,就像一个书架,里面有很多书。 它显示所有带卷轴的书。选择其内容的书籍将显示在窗口中。 但若出于某种原因,我想从代码隐藏改为另一本书,它会将其内容更新到webbrowser,但不会将该书的列表框更新为SelectedItem

回答: 好吧,我现在找到答案了。设置BookShelf.SelectedItem=dbInfo的代码应该是bookShelfViewModel.SelectedItem=bookShelfViewModel.BookShelf.First(x=>x.DbId==dbInfo.DbIf)

看起来不太好,你在哪里做的?我建议使用ViewModelLocator来设置DataContext(可通过nuget获得)。它为您提供了一个ViewModelBase,以及您所有的属性更改需求和工作,您可以扩展它以满足您的需求。听起来像是DataContext,如果PropertyChanged甚至没有被提出,这可能是实际的问题

编辑:

,因为它是
SelectedItem
属性的默认值,所以我将把它作为一个示例

<ComboBox Margin="8,15,0,0" Name="bookShelf_ComboBox" ItemsSource="{Binding BookShelf}"  SelectedItem="{Binding SelectedItem, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" DisplayMemberPath="DisplayName" Height="22" Width="140" Visibility="Visible">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <command:EventToCommand Command="{Binding SelectedItemChangedCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>


我注意到代码中的SelectionChanged=“bookShelf\u ComboBox\u SelectionChanged”,这是“讨厌的”,请改用event to命令,因为您正在将viewmodel绑定到views cbox。上面的代码将执行包含参数的命令,将以下内容添加到viewmodel中

public ICommand SelectedItemChangedCommand{ get; set;}

// somewhere in your code..
SelectedItemChangedCommand = new RelayCommand<SelectedItemChangedCommand>(OnSelectedItemChanged);

protected void OnSelectedItemChanged(SelectedItemChangedCommand e)
{
   // Do your magic here! Or why not just call this method from the setter of your bound property?
}
public ICommand选择editemchangedcommand{get;set;}
//在代码的某个地方。。
选择EditemChangedCommand=new RelayCommand(在SelectedItemChanged上);
SelectEditemChanged(SelectedItemChangedCommand e)上的受保护无效
{
//在这里施展你的魔法!或者为什么不直接从绑定属性的setter调用这个方法呢?
}
是一个很好的所有类型绑定的紧凑列表,非常方便,我在学习WPF时,在家里和墙上都有它:)

希望能有帮助

干杯


斯蒂安

你所说的用户界面没有更新是什么意思?您设置了一个新的ItemsSource,但没有看到任何更改

如果是这种情况,请将您的财产更改为

public ObservableCollection<DbInfo> BookShelf
{
    get
    {
        if (_BookShelf == null)
            _BookShelf = new ObservableCollection<DbInfo>();
        return _BookShelf;
    }
    set
    {
        if (value != _BookShelf)
        {   _BookShelf = value;
            RaisePropertyChanged(new PropertyChangedEventArgs("BookShelf"));
        }
    }
公共可观察收集书架
{
得到
{
if(_BookShelf==null)
_BookShelf=新的ObservableCollection();
归还书架;
}
设置
{
如果(值!=\u书架)
{{u BookShelf=value;
RaisePropertyChanged(新的属性更改开发标签(“书架”);
}
}
顺便说一句,我用另一种方式使用ObservableCollection。我只需初始化它一次,然后使用Clear、Add、Remove


如果项目资源不是您的问题,请发布DbInfo的代码,并在“UI未更新”问题中写入更多内容。好的,我现在找到了答案。设置BookShelf.SelectedItem=DbInfo的代码应该是bookShelfViewModel.SelectedItem=bookShelfViewModel.BookShelf.First(x=>x.DbId==DbInfo.DbIf)

是否检查了XAML上的绑定模式?如果从视图更新视图模型并从视图更新视图,则需要使用双向模式model@aggietech您的意思是SelectedItem绑定?默认情况下,该属性是双向绑定的。bookShelf\u ComboBox\u SelectionChanged没有触发任何操作,对吗?您正在尝试若要获取“SelectionChanged”事件以在视图模型中触发命令?具体如何定义DataContext?如果您确定引发了PropertyChanged事件,但UI未更新,我认为DataContext设置不正确。@Jon Koivula有人问了与您相同的问题(至少在同一时间),我给出了一个示例解决方案,如果您愿意,请检查它并将其应用于您的模型。默认情况下WPF不是双向绑定吗?Silverlight是单向的-这让我多次困惑…无论如何,最安全的方法是始终指定它explicitly@sondergard不,默认值是单向的,就像SL=)@Stian一样。这是错误的。一些依赖属性绑定双向默认情况下。例如SelectedItem有。请查看依赖项属性信息。@Clemens-Hmm我实际上没有意识到这一点,发现了另一个WPF异常;)您完全正确+1不是一个异常,只是一个功能。如果您仔细想想,它非常有意义。列表框显示了我的ObservableCollection拥有的所有项,但它没有选择在列表框中选择该项,无论其值是多少BookShelfViewModel.SelectedItem。除非单击列表框中的项,否则它只会被选中,而不会被代码隐藏
public class DbInfo
{
    public int RelatedId { get; set; }
    public string DbId { get; set; }
    public TBase3.Article currentArticle { get; set; }
    public string LinkId { get; set; }
    public bool IsArticle { get; set; }
    public string folder { get; set; }
    public bool IsNamedArticle { get; set; }
    public int currentBlockIndex { get; set; }
    public int currentBlockCount { get; set; }
    public string DisplayName { get; set; }
    public int VScrollPos { get; set; }
    public int THTextVersion { get; set; }
    public bool isHtmlToc { get; set; }
    public ImageSource bookImage { get; set; }
}
await System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => this.BookShelf.DataContext = bookShelfViewModel));
<ComboBox Margin="8,15,0,0" Name="bookShelf_ComboBox" ItemsSource="{Binding BookShelf}"  SelectedItem="{Binding SelectedItem, Mode=TwoWay}" VerticalAlignment="Center" HorizontalAlignment="Center" DisplayMemberPath="DisplayName" Height="22" Width="140" Visibility="Visible">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <command:EventToCommand Command="{Binding SelectedItemChangedCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ComboBox>
public ICommand SelectedItemChangedCommand{ get; set;}

// somewhere in your code..
SelectedItemChangedCommand = new RelayCommand<SelectedItemChangedCommand>(OnSelectedItemChanged);

protected void OnSelectedItemChanged(SelectedItemChangedCommand e)
{
   // Do your magic here! Or why not just call this method from the setter of your bound property?
}
public ObservableCollection<DbInfo> BookShelf
{
    get
    {
        if (_BookShelf == null)
            _BookShelf = new ObservableCollection<DbInfo>();
        return _BookShelf;
    }
    set
    {
        if (value != _BookShelf)
        {   _BookShelf = value;
            RaisePropertyChanged(new PropertyChangedEventArgs("BookShelf"));
        }
    }