如果文本框发生更改,如何获取事件?

问题描述 投票:0回答:1

我通过外部 yaml 文件进行了复杂的模型设计,并将视图添加为后面的代码。需要这种结构是因为我构建了一种配置管理器,用户可以在其中通过 yaml 文件创建视图布局。用户界面对我来说工作得很好,所以我得到了包含所有信息的正确视图。还会显示表单元素内的默认值和占位符。但我就是无法将更改后的表单元素返回到后面的代码。

首先,我尝试将模型添加为

ObservableObject 
,但更改后的事件侦听器不会被触发。然后我想我需要绑定一些值。所以我尝试了自定义绑定,但我就是无法运行它。 那么也许文本框元素有一些
OnChangeText 
属性,但实际上没有。

我正在使用一些库,例如 Lepo 的 CommunityToolkit 和 WPF-UI(用于 UI 元素)

Xaml:
<Page x:Class="ProjektName.Views.Pages.Server.ServerTemplatePage"
      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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
      xmlns:controls="clr-namespace:ArkServerManager.Controls"
      xmlns:lang="clr-namespace:ProjektName.Languages"
      xmlns:models="clr-namespace:ProjektName.Models"
      xmlns:local="clr-namespace:ProjektName.Views.Pages.Server"
      mc:Ignorable="d"
      d:DataContext="{d:DesignInstance local:ServerTemplatePage,
                                       IsDesignTimeCreatable=False}"
      d:DesignHeight="650"
      d:DesignWidth="800"
      Title="ServerAdministrationPage"
      ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
      ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
      Foreground="{DynamicResource TextFillColorPrimaryBrush}">
    <StackPanel>
        <ContentPresenter Content="{Binding ViewModel.RootSections}" />
    </StackPanel>
</Page>
背后的Xaml:
public partial class ServerTemplatePage : INavigableView<ServerTemplateViewModel>
{
    public ServerTemplateViewModel ViewModel { get; }
    
    public ServerTemplatePage(ServerTemplateViewModel viewModel)
    {
        ViewModel = viewModel;
        DataContext = this;
        
        InitializeComponent();
    }
}
视图模型:
public partial class ServerTemplateViewModel : ObservableObject, INavigationAware
{
    private ServerSettingsConfigModel? _config;

    [ObservableProperty] private ObservableCollection<ServerSettingsConfigModel.SettingsSection>? _sections;

    [ObservableProperty] private ObservableCollection<ServerSettingsConfigModel.SettingsSection> _areas;

    [ObservableProperty] private StackPanel _rootSections = new();

    [ObservableProperty] private ServerSettingsModel _serverSettingsModel = new();

    [ObservableProperty] private int _test;
    [ObservableProperty] private string _testString = string.Empty;

    // private ObservableCollection<ServerSettingsModel> _serverSettingsModel;
    // public ObservableCollection<ServerSettingsModel> ServerSettingsModel {
    //     get => _serverSettingsModel;
    //     set
    //     {
    //         ServerSettingsModel = value;
    //         OnPropertyChanged("Text");
    //     }
    // }

    // private int _name;
    //
    // public int Name
    // {
    //     get => _name;
    //     set
    //     {
    //         _name = value;
    //         OnPropertyChanged("Name");
    //     }
    // }

    public void OnNavigatedTo()
    {
        _config = ConfigUtils.GetServerNavigationConfig("Administration");
        Sections = _config.Items;
        CreateView();


        // Areas = _config.Items.ToObservableCollection();
    }

    private void CreateView()
    {
        if (Sections == null)
        {
            return;
        }

        foreach (var section in Sections)
        {
            RootSections.Children.Add(new TextBlock
            {
                Text = section.Text,
                Margin = new Thickness(0, 10, 0, 10),
                FontTypography = FontTypography.BodyStrong
            });
            foreach (var property in section.Props)
            {
                RootSections.Children.Add(new CardControl
                {
                    Header = new DefaultCardControlHeader
                    {
                        Title = property.Text,
                        Description = property.Description
                    },
                    Content = GetInputElement(property)
                });
            }
        }
    }

    private Control GetInputElement(ServerSettingsConfigModel.SettingsSection.SectionProperty property)
    {
        switch (property.Type)
        {
            case "int":
                var numberBox = new NumberBox
                {
                    Value = property.Default?.ConvertValueToInt(),
                    PlaceholderText = property.Placeholder,
                    MinWidth = 200
                };
                // var numberBinding = new Binding("ViewModel.Name")
                // {
                //     Mode = BindingMode.TwoWay
                // };
                var numberBinding = new Binding("Test")
                {
                    Source = Test
                };
                numberBox.SetBinding(NumberBox.ValueProperty, numberBinding);
                return numberBox;
            case "bool":
                var toggleSwitch = new ToggleSwitch
                {
                    IsChecked = property.Default?.ConvertValueToBool(),
                    OnContent = property.OnText,
                    OffContent = property.OffText
                };
                return toggleSwitch;
            // Default and for textboxes
            default:
                var textBox = new System.Windows.Controls.TextBox()
                {
                    // Text = property.Default?.ToString() ?? string.Empty,
                    // PlaceholderText = property.Placeholder,
                    MinWidth = 200,
                };
                var textBinding = new Binding("ViewModel.TestString")
                {
                    Source = TestString,
                    Mode = BindingMode.TwoWay
                };
                textBox.SetBinding(System.Windows.Controls.TextBox.TextProperty, textBinding);
                return textBox;
        }
    }

    public void OnNavigatedFrom()
    {
        Console.WriteLine();
    }
}
服务器设置配置模型
public partial class ServerSettingsConfigModel : ObservableObject
{
    public string filename = null!;
    
    #region Config properties

    [ObservableProperty] private string _name = null!;
    [ObservableProperty] private string _icon = null!;
    [ObservableProperty] private ObservableCollection<SettingsSection> _items = null!;
    public partial class SettingsSection : ObservableObject
    {
        [ObservableProperty] private string _text = null!;
        [ObservableProperty] private ObservableCollection<SectionProperty> _props = null!;
        public partial class SectionProperty : ObservableObject
        {
            [ObservableProperty] private string _id = null!;
            [ObservableProperty] private string _text = null!;
            [ObservableProperty] private string _onText = null!;
            [ObservableProperty] private string _offText = null!;
            [ObservableProperty] private string _description = null!;
            [ObservableProperty] private object? _default;
            [ObservableProperty] private string _type = null!;
            [ObservableProperty] private bool _isOptional;
            [ObservableProperty] private bool _isPassword;
            [ObservableProperty] private string _placeholder = null!;
        }
    }

    #endregion
}
c# wpf data-binding 2-way-object-databinding community-toolkit-mvvm
1个回答
0
投票

我对你的问题的想法:

我将使用

itemControl template
ObservableCollection<TextBoxViewModel>
来注册文本框:

<!-- MainWindow -->
<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:YourNamespace"
        mc:Ignorable="d"
        xmlns:controls="clr-namespace:Microsoft.Toolkit.Wpf.UI.Controls;assembly=Microsoft.Toolkit.Wpf.UI.Controls"
        Title="MainWindow" Height="350" Width="525">

    <StackPanel>
        <!-- Other UI elements -->
        <Button Content="Add TextBox" Command="{Binding AddTextBoxCommand}" />
        <ItemsControl ItemsSource="{Binding TextBoxes}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                             TextChanged="TextBox_TextChanged" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Window>

创建动态文本框的视图模型示例已更改:

// MainViewModel
using System.Collections.ObjectModel;
using System.Windows.Input;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;

namespace YourNamespace
{
    public class MainViewModel : ObservableObject
    {
        private ObservableCollection<TextBoxViewModel> textBoxes = new ObservableCollection<TextBoxViewModel>();

        public ObservableCollection<TextBoxViewModel> TextBoxes
        {
            get { return textBoxes; }
            set { SetProperty(ref textBoxes, value); }
        }

        public ICommand AddTextBoxCommand { get; }

        public MainViewModel()
        {
            AddTextBoxCommand = new RelayCommand(AddTextBox);
        }

        private void AddTextBox()
        {
            TextBoxViewModel newTextBox = new TextBoxViewModel();
            TextBoxes.Add(newTextBox);
        }

        private void TextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
        {
            // Handle the TextBox text changed event here
            var textBox = (System.Windows.Controls.TextBox)sender;
            string newText = textBox.Text;
            // Do something with the new text...
        }
    }

    public class TextBoxViewModel : ObservableObject
    {
        private string text;

        public string Text
        {
            get { return text; }
            set { SetProperty(ref text, value); }
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.