通过MVVM中的INotify将字符串从一个用户控件传递到第二个用户控件

时间:2011-05-24 19:47:40

标签: silverlight mvvm c#-4.0 inotifypropertychanged

我在通过INotify将字符串从一个用户控件传递到第二个用户控件时遇到了一些问题。

在视图中我有一个列表框,当用户在用户控件中的文本框中键入值时,该列表框绑定到名为SearchHistory的类型字符串的ObservableCollection,我将输入的值传递给集合并在列表框中显示控制(某些条款的历史输入)。这很好用。

我现在正尝试选择列表框项目并通过INotifyPropertyChanged将其传回控件中的文本框。虽然我看到选定的值被传递回视图模型中的属性,但它不会使用新选择的值更新视图中的文本框。

在我的视图中,我为列表框项目提供了以下xaml

<ListBox Margin="0,0,1,0"
                         Background="{x:Null}"
                         BorderBrush="{x:Null}"
                         BorderThickness="0"
                         ItemsSource="{Binding SearchHistory}" 
                         SelectionChanged="ListBox_SelectionChanged" />

在视图代码隐藏中,我有以下内容(我选择将此放在后面的代码中,因为在两个控件之间传递字符串时,该功能特定于视图。我不认为这需要在viewmodel中一个命令,但如果是,请让我知道否则)

    public partial class viewSearch : Page
{
    private SearchViewModel _ViewModel;

    #region Constructor
    public viewSearch()
    {
        InitializeComponent();
        CloseFilterPanel();
        CloseHistoryPanel();
        CloseSaveSearchPanel();
        this._ViewModel = new SearchViewModel();
        this.DataContext = this._ViewModel;
    }

...为简洁而编辑

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if(((ListBox)sender).SelectedItem != null)
        _ViewModel.SearchTerm = (((ListBox)sender).SelectedItem.ToString());
        this.NotifyPropertyChanged(_ViewModel.SearchTerm);
    }

在ViewModel中,我还声明了公共属性SearchTerm

        public string SearchTerm
    {
        get
        {
            return this._SearchTerm;
        }
        set
        {
            if (this._SearchTerm == value)
                return;

            // Set the new value and notify
            this._SearchTerm = value;
            this.NotifyPropertyChanged("SearchTerm"); //this binds to UI search textbox
       }

正如我所说,当我逐步执行此操作时,值将从视图传递到视图模型,我看到上面的属性已更新,但是当它遇到绑定到UI的部分时,UI中没有任何内容发生。

下面是包含文本块的usercontrol的部分(我排除了网格包装器和标头上下文)xaml。当我从父视图继承数据上下文时,控件中没有设置数据上下文。

<TextBox x:Name="txtSearchField"
        Grid.Column="0"
        Margin="5,3,5,1.333"
        ap:AttachedProperties.InitialFocus="True"
        FontSize="16"
        KeyDown="txtSearchField_KeyDown"
        Padding="2,5,10,1"
        Style="{StaticResource SearchTxtBoxStyle}"
        Text="{Binding SearchTerm, Mode=TwoWay}"
        TextAlignment="Right"
        ToolTipService.ToolTip="{StaticResource TTsearchField}">
        <i:Interaction.Triggers>
            <ei:KeyTrigger FiredOn="KeyUp" Key="Enter">
                <i:InvokeCommandAction Command="{Binding GetSearchResultCommand, Mode=OneWay}"/>
            </ei:KeyTrigger>
        </i:Interaction.Triggers>           
    </TextBox>

最后控件放在主视图中

<srch:SearchControl x:Name="ucSearchControl" DataContext="{Binding}" Grid.Row="0" />

任何提示或建议表示赞赏。 提前谢谢

3 个答案:

答案 0 :(得分:0)

通过这个,我发现问题在于尝试将字符串传递回属性以及我最初如何将我的值存储在泛型集合中。以下是我解决问题的方法。

我们将首先在搜索用户控件中使用xaml。该控件包含我想要更新的文本字段。

<TextBox x:Name="txtSearchField"
        Grid.Column="0"
        Margin="5,3,5,1.333"
        ap:AttachedProperties.InitialFocus="True"
        FontSize="16"
        KeyDown="txtSearchField_KeyDown"
        Padding="2,5,10,1"
        Style="{StaticResource SearchTxtBoxStyle}"
        Text="{Binding SearchTerm, Mode=TwoWay}"
        TextAlignment="Right"
        ToolTipService.ToolTip="{StaticResource TTsearchField}">
        <i:Interaction.Triggers>
            <ei:KeyTrigger FiredOn="KeyUp" Key="Enter">
                <i:InvokeCommandAction Command="{Binding GetSearchResultCommand, Mode=OneWay}"/>
            </ei:KeyTrigger>
        </i:Interaction.Triggers>           
    </TextBox>

在ViewModel中,我声明了一个新的集合

委托命令

private ObservableCollection<SearchHistoryModel> _SearchHistory = new ObservableCollection<SearchHistoryModel>();

创建了我的属性

public ObservableCollection<SearchHistoryModel> SearchHistory
    {

        get
        {
            return this._SearchHistory;
        }
        private set
        {
            if (this._SearchHistory == value)
                return;
            this._SearchHistory = value;
            this.NotifyPropertyChanged("SearchHistory");
        }
    }

对模型的命令

private void GetSearchResultCommandExecute(object parameter)
    {
        //query
       this.SearchResults = this._DataModel.GetSearchResults(this.SearchTerm);
        //search history items
      this.SearchHistory = this._DataModel.AddSearchHistoryItem(this.SearchTerm);
    }

在Model I中,然后创建了一个方法,将字符串添加到我的集合

委托命令

private ObservableCollection<SearchHistoryModel> SearchHistory = new ObservableCollection<SearchHistoryModel>();

方法

public ObservableCollection<SearchHistoryModel>AddSearchHistoryItem(string searchHistoryItem)
    {
        SearchHistoryModel shm = new SearchHistoryModel();
        shm.SearchHistoryString = searchHistoryItem.ToString();
        SearchHistory.Add(shm);
        return this.SearchHistory;
            //this.SearchHistory = new ObservableCollection<SearchHistoryModel>();
            //this.SearchHistory.Add(searchHistoryItem);                 
    }

采用这条路线,我可以将集合推回到UI,然后将其绑定到Listbox

然后在我的视图中,我可以使用选择更改事件来更新搜索历史可观察集合。虽然我不是100%肯定,但我认为问题与observable集合如何处理NotificationChanged事件有关。如果有人对此有任何额外的见解,我将不胜感激。

后面的seach.xaml.cs代码

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (((ListBox)sender).SelectedItem != null)
            _ViewModel.SearchTerm = (((ListBox)sender).SelectedItem as SearchHistoryModel).SearchHistoryString.ToString();
        this.NotifyPropertyChanged(_ViewModel.SearchTerm);
    }

*为清楚起见,注意SearchHistoryModely只包含一个名为SearchHistoryString的哑属性

 public class SearchHistoryModel
{
    public string SearchHistoryString { get; set; }
}

这里要注意的主要是我将Listbox项目转换为我的集合/属性。由于项目永远不可见,除非他们有一个对象,我没有测试空值,但我想我会稍后再回来更新,只是为了整洁。

现在进行这些更改允许我将列表框集合中的项目传递回textBlock字段(反之亦然)。

我欢迎任何其他替代或更简化的解决方案。 谢谢

答案 1 :(得分:0)

它没有经过测试,但是当您只想将listitem从列表框设置为textbox.text属性时,这将起作用:(我假设您的TextBox的名称是txtSearch)

 <ListBox Margin="0,0,1,0"
                     Background="{x:Null}"
                     BorderBrush="{x:Null}"
                     BorderThickness="0"
                     ItemsSource="{Binding SearchHistory}" 
                     SelectedItem="{Binding ElementName=txtSearch, Path=Text, Mode=OneWayToSource}" />

答案 2 :(得分:0)

如果我理解正确,有一种非常简单的方法可以用“MVVM”方式实现你想要做的事情。

您可以将SelectedItem“TwoWay”中的ListBox绑定到第一个控件的ViewModel中的属性。在该属性的setter中,您可以发送消息,例如SearchTermSelectedMessage,这将由其他控件的ViewModel接收,并相应地设置属性,这将更新UI。为此,您可以使用MVVMLightMessenger对象。

希望这有帮助。