【问题标题】:xaml Textbox two way binding doesn't update code variablexaml 文本框双向绑定不更新代码变量
【发布时间】:2021-10-11 04:01:46
【问题描述】:

我遇到了 XAML 绑定问题:
我有一个带绑定的文本框,但是当我打印出绑定到文本框文本的值时,它是一个空字符串。

我尝试过的:
我尝试了不同的 UpdateSourceTriggers,并查看了 Stackoverflow。

(顺便说一句,我对 MVVM 比较陌生,这是我的第一个更大的项目)

我的 SearchView.xaml

<UserControl x:Class="MovieDatabase.MVVM.View.SearchView"
             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:MovieDatabase.MVVM.View" 
             xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:viewmodel="clr-namespace:MovieDatabase.MVVM.ViewModel"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800"
             KeyUp="SearchMovie">

    <UserControl.DataContext>
        <viewmodel:SearchViewModel/>
    </UserControl.DataContext>

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

        <StackPanel Orientation="Horizontal"
                    VerticalAlignment="Top"
                    HorizontalAlignment="Stretch">
            
            <TextBox Style="{StaticResource ModernSearchBar}"
                     Text="{Binding Path=SearchContent, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                     TextChanged="TextBox_TextChanged"/>
            <TextBlock Margin="10"
                       Text="Search for: "
                       Foreground="White"
                       FontSize="16"/>
            <ComboBox Style="{StaticResource FlatCombobox}"
                      ItemsSource="{Binding SearchList}"
                      SelectedIndex="{Binding Path=SelectedSearchIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                      Width="100"/>

        </StackPanel>

(我的问题与第一个文本框有关)

我的 SearchView.xaml.cs

using MovieDatabase.MVVM.ViewModel;
using System.Windows.Controls;
using System.Windows.Input;


namespace MovieDatabase.MVVM.View
{
    public partial class SearchView : UserControl
    {
        public static SearchView Instance { get; set; }
        public SearchView()
        {
            InitializeComponent();
            DataContext = MainViewModel.SearchVM;
            Instance = this;
        }

        private void SearchMovie(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                MainViewModel.SearchVM.Search();
            }
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); // Doesn't seem to help
        }
    }
}

我的 SearchViewModel.cs(不完整,完整的类会太多)

using MovieDatabase.Core;
using MovieDatabase.MovieSpace;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows;
using MovieDatabase.Util;
using System.Windows.Media.Imaging;
using System;

namespace MovieDatabase.MVVM.ViewModel
{
    public class SearchViewModel : ObservableObject
    {

        private string _searchContent;
        public string SearchContent
        {
            get { return _searchContent; }
            set
            {
                _searchContent = value;
                OnPropertyChanged(nameof(SearchContent));
            }
        }
        // When this method is called, SearchContent is ""
        public void Search()
        {
            List<Movie> movies = new List<Movie>();
            MessageBox.Show(SearchContent);
            MainViewModel.logger.Log(Levels.INFO, $"User searching for {SearchContent} in Category {SearchList[SelectedSearchIndex]}");

            if (SearchList[SelectedSearchIndex] == SearchList[0])
            {
                foreach (Movie movie in Movie.AllMovies)
                {
                    if (movie.Info.title.Contains(SearchContent))
                    {
                        movies.Add(movie);
                    }
                }

            } else if (SearchList[SelectedSearchIndex] == SearchList[1])
            {
                foreach (Movie movie in Movie.AllMovies)
                {
                    if (movie.Info.stars.Contains(SearchContent))
                    {
                        movies.Add(movie);
                    }
                }

            } else if (SearchList[SelectedSearchIndex] == SearchList[2])
            {
                foreach (Movie movie in Movie.AllMovies)
                {
                    if (movie.Info.year == SearchContent)
                    {
                        movies.Add(movie);
                    }
                }

            } else if (SearchList[SelectedSearchIndex] == SearchList[3])
            {
                foreach (Movie movie in Movie.AllMovies)
                {
                    if (movie.Info.genres.Contains(SearchContent))
                    {
                        movies.Add(movie);
                    }
                }
            }
            if (movies.Count == 0)
            {
                return;
            }
            foreach (Movie mov in movies)
            {
                AddMovieToView(mov.Info.title);
            }
        }
    }
}

我的可观察对象类

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MovieDatabase.Core
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

【问题讨论】:

    标签: c# wpf xaml binding


    【解决方案1】:

    您展示了 MainViewModel 类的不完整代码。
    它遗漏了一个非常重要的细节:SearchVM 属性的实现。
    问题的最明显原因是您在 XAML 中创建了 MainViewModel 类的新实例。
    在后面的代码中,您指的是存储在 MainViewModel.SearchVM 属性中的此类的另一个实例。

    如果没有更完整的代码,很难确切地知道如何修复它。 尝试以下更改。

    namespace MovieDatabase.MVVM.ViewModel
    {
        public class SearchViewModel : ObservableObject
        {
            publis static SearchViewModel Instance {get;}
                = new SearchViewModel ();
    
            // It's better to hide the constructor
            private SearchViewModel()
            {
                // Some code
            }
    
    namespace MovieDatabase.MVVM.View
    {
        public partial class SearchView : UserControl
        {
            public static SearchView Instance { get;} = new SearchView();
            private SearchView()
            {
                InitializeComponent();
                // DataContext = MainViewModel.SearchVM;
                // Instance = this;
            }
    
            private void SearchMovie(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Enter)
                {
                    MainViewModel.Instance.Search();
                }
            }
    
            // private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
            // {
            //     TextBox textBox = sender as TextBox;
            //     textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); // Doesn't seem to help
            // }
        }
    }
    
    <UserControl x:Class="MovieDatabase.MVVM.View.SearchView"
                 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:MovieDatabase.MVVM.View" 
                 xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
                 xmlns:viewmodel="clr-namespace:MovieDatabase.MVVM.ViewModel"
                 mc:Ignorable="d"
                 d:DesignHeight="450" d:DesignWidth="800"
                 KeyUp="SearchMovie"
                 DataContext="{x:Static viewmodel:SearchViewModel.Instance}">
    
        <!--<UserControl.DataContext>
            <viewmodel:SearchViewModel/>
        </UserControl.DataContext>-->
    

    很遗憾,这没有帮助。

    项目中有很多错误。
    部分纠正了它们。
    但即使是这个部分修复也太大了,无法在此处发布。
    向我发送“邀请合作者”,我会将这些更改提交到您的存储库。

    主要错误是TextBox的模板设置不正确。

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
        <Style TargetType="{x:Type TextBox}"
               x:Key="ModernSearchBar">
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="5"/>
            <Setter Property="Foreground" Value="LightGray"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBox}">
                        <Border CornerRadius="10"
                                Background="#353340"
                                Width="200"
                                Height="40">
                            <Grid>
                                <Rectangle StrokeThickness="1"/>
    
                                <!--Instead of giving the TextBox a place to display its text,
                                you've overlaid another TextBox on top of it.
                                And property values must be set in Style Setters.-->
                                <!--<TextBox Margin="1"
                                         Text="{TemplateBinding Text}"
                                         BorderThickness="0"
                                         Background="Transparent"
                                         VerticalContentAlignment="Center"
                                         Padding="5"
                                         Foreground="#CFCFCF"
                                         x:Name="SearchBar"/>-->
                                
                                <!--This element is required in the TextBox template. 
                                It is he who is looked for by the TextBox logic to display the text.-->
                                <ScrollViewer Margin="0" x:Name="PART_ContentHost" Padding="5"/>
                                
                                <TextBlock IsHitTestVisible="False"
                                           Text="Search"
                                           VerticalAlignment="Center"
                                           HorizontalAlignment="Left"
                                           Margin="10,0,0,0"
                                           FontSize="11"
                                           Foreground="DarkGray"
                                           Grid.Column="1">
    
                                    <TextBlock.Style>
                                        <Style TargetType="{x:Type TextBlock}">
                                            <Style.Triggers>
                                                <DataTrigger Binding="{Binding Text.IsEmpty, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=TextBox}}"
                                                             Value="True">
                                                    <Setter Property="Visibility" Value="Visible"/>
                                                </DataTrigger>
                                            </Style.Triggers>
                                            <Setter Property="Visibility" Value="Hidden"/>
                                        </Style>
                                    </TextBlock.Style>
                                    
                                </TextBlock>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            
        </Style>
        
    </ResourceDictionary>
    

    【讨论】:

    • 您好,感谢您的回答!不幸的是,这没有帮助。这是我的github repository 的所有文件的链接,我几分钟前刚刚更新,所以文件与我电脑上的文件相同
    • 给我发送“邀请合作者”。
    • 我补充了我的答案。阅读本补充材料。
    • 天哪,现在可以了,非常感谢!我已经向 EldHasp 发送了邀请,我猜是你。
    • 我创建了“eldhasp”分支并提交了更改。
    猜你喜欢
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    • 2018-06-12
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多