gpt4 book ai didi

c# - 如何在代码隐藏中将自定义属性从 View 绑定(bind)到 ViewModel?

转载 作者:太空宇宙 更新时间:2023-11-03 15:32:46 25 4
gpt4 key购买 nike

我制作了一个 Page MainPage 和一个 UserControl Pager。两者都有自己的 ViewModel。在Pager中,存在三个依赖属性RowsColumnsSource。我想将这些属性从 Pager 的 View 传递到 Pager 的 ViewModel。我在 View 的代码后面试过这个。但它不起作用...PagerViewModel 中的 set 属性永远不会在调试时被调用。请帮帮我...

这里是详细机制:

MainPageViewModel

↓通过绑定(bind)传递值

主页

↓使用 MainPagerViewModel

中的值设置属性

寻呼机(代码隐藏)

↓将属性绑定(bind)到 PagerViewModel <--- 这部分是问题!!!

PagerViewModel

↓通过绑定(bind)传递值

寻呼机(XAML)

这是来源

[MainPageViewModel.cs]

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using Client.Model;

namespace Client.ViewModel
{
public class MainPageViewModel : ViewModelBase
{
...
public ObservableCollection<IPagableEntry> PagerTableCategoriesItems { get { return TableCategoryRepository.Instance.TableCategories; } }

public int PagerTableCategoriesRows { get { return 1; } }

public int PagerTableCategoriesColumns { get { return 3; } }
...
}
}

[主页.xaml]

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:Client.View"
xmlns:viewModel="clr-namespace:Client.ViewModel"
xmlns:resStr="clr-namespace:Client.CommonResources.String"
x:Class="Client.View.MainPage"
Style="{StaticResource common}">
<Page.DataContext>
<viewModel:MainPageViewModel />
</Page.DataContext>
...

<view:Pager x:Name="pagerTableCategories"
Source="{Binding Path=PagerTableCategoriesItems}"
Rows="{Binding Path=PagerTableCategoriesRows}"
Columns="{Binding Path=PagerTableCategoriesColumns}">
</view:Pager>
...
</Page>

[Pager.xaml.cs]

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using Client.Model;
using Client.ViewModel;

namespace Client.View
{
public partial class Pager
{

public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ObservableCollection<IPagableEntry>), typeof(Pager), new PropertyMetadata(null, OnSourceChanged));
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register("Rows", typeof(int), typeof(Pager), new PropertyMetadata(1, OnRowsChanged));
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns", typeof(int), typeof(Pager), new PropertyMetadata(1, OnColumnsChanged));
public static readonly DependencyProperty SelectedEntryProperty = DependencyProperty.Register("SelectedEntry", typeof(object), typeof(Pager), new PropertyMetadata(null, OnSelectedEntryChanged));

public int Rows
{
get { return (int)GetValue(RowsProperty); }
set { SetValue(RowsProperty, value); }
}

public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}

public object SelectedEntry
{
get { return GetValue(SelectedEntryProperty); }
set { SetValue(SelectedEntryProperty, value); }

}

public ObservableCollection<IPagableEntry> Source
{
get { return (ObservableCollection<IPagableEntry>)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}

public Pager()
{
InitializeComponent();

// I want to bind the three custom properties(Rows, Columns, Source) to PagerViewModel's Rows, Columns, Collection
Binding bindingRows = new Binding("Rows");
bindingRows.Mode = BindingMode.TwoWay;
bindingRows.Source = gridPager.DataContext;
gridPager.SetBinding(RowsProperty, bindingRows);

Binding bindingColumns = new Binding("Columns");
bindingColumns.Mode = BindingMode.TwoWay;
bindingColumns.Source = gridPager.DataContext;
gridPager.SetBinding(ColumnsProperty, bindingColumns);

Binding bindingSource = new Binding("Collection");
bindingSource.Mode = BindingMode.TwoWay;
bindingSource.Source = gridPager.DataContext;
gridPager.SetBinding(SourceProperty, bindingSource);
}

private void ListBoxEntriesOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedEntry = (sender as ListBox).SelectedItem;
}

private static void OnSelectedEntryChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
(pager as Pager).SelectedEntry = e.NewValue;
}

private static void OnSourceChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
(pager as Pager).Source = (ObservableCollection<IPagableEntry>)e.NewValue;
}

private static void OnRowsChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
(pager as Pager).Rows = (int)e.NewValue;
}

private static void OnColumnsChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
(pager as Pager).Columns = (int)e.NewValue;
}

}
}

[寻呼机.xaml]

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:Client.View"
xmlns:viewModel="clr-namespace:Client.ViewModel"
xmlns:resStr="clr-namespace:Client.CommonResources.String"
x:Class="Client.View.Pager">
<Grid x:Name="gridPager">
<Grid.DataContext>
<viewModel:PagerViewModel />
</Grid.DataContext>

...

<ListBox x:Name="listBoxEntries"
ItemsSource="{Binding Path=Collection}"
BorderThickness="0"
Margin="0"
Style="{StaticResource common}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
ItemTemplate="{StaticResource templateTableCategory}"
SelectedItem="{Binding Path=SelectedEntry, Mode=TwoWay}"
SelectionChanged="ListBoxEntriesOnSelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding Path=Rows}"
Columns="{Binding Path=Columns}"
IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

...

</Grid>
</UserControl>

[PagerViewModel.cs]

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Data;
using System.Windows.Media;
using Client.Model;

namespace Client.ViewModel
{
public class PagerViewModel : ViewModelBase
{

...

ListCollectionView _listCollectionView;
ObservableCollection<IPagableEntry> _collection;
int _rows;
int _columns;

public int Rows
{
get { return _rows; }
set
{
_rows = value;
OnPropertyChanged();
}
}

public int Columns
{
get { return _columns; }
set
{
_columns = value;
OnPropertyChanged();
}
}

public ListCollectionView ListCollectionView
{
get { return _listCollectionView; }
set
{
_listCollectionView = value;
OnPropertyChanged();
}
}

public ObservableCollection<IPagableEntry> Collection
{
get
{
return _collection;
}

set
{
_collection = value;
OnPropertyChanged();
}
}

...

}
}

最佳答案

您发布的代码有两个明显的问题:

  1. 您的 OnXXXChanged() 处理程序不执行任何操作。他们正在响应他们反过来试图设置的属性的变化。 IE。他们只是重申他们收到通知的属性设置,而不是在某个不同的对象中设置属性值。
  2. 您正试图对不存在的属性设置绑定(bind)。 IE。您的代码隐藏 SetBinding() 调用的目标是 gridPager 对象,它只是一个 Grid。它没有要设置的任何 RowsColumnsSource 属性。

暂时假设我们将使用绑定(bind)来完成此操作,您会遇到第三个问题:

  1. 您会尝试将两个不同的源属性绑定(bind)到同一个目标属性。例如。 Pager.Rows 已经是在 MainPage.xaml 中建立的绑定(bind)的目标,以 PagerTableCategoriesRows 作为源。它也不能是来自任何其他对象的绑定(bind)的目标(最重要的是,来自其自身的循环绑定(bind),如果使用 Pager.RowsProperty 依赖属性,这是唯一有意义的来源,正如代码试图做的那样)。

我什至不完全清楚这样做是否明智。看起来 Pager 元素本身可以直接绑定(bind)到 Pager 属性,从而从原始 View 模型继承值,而不是维护第二个完全独立但有意的 -相同的 View 模型。

但是假设,有一些我根本不明白的非常充分的理由,你打算在这里使用两个不同的 View 模型并想让它们保持同步,在我看来你应该能够让它工作通过更改您的 OnXXXChanged() 处理程序,以便它们直接设置 View 模型值。例如:

public partial class Pager
{

public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(ObservableCollection<IPagableEntry>), typeof(Pager), new PropertyMetadata(null, OnSourceChanged));
public static readonly DependencyProperty RowsProperty = DependencyProperty.Register("Rows", typeof(int), typeof(Pager), new PropertyMetadata(1, OnRowsChanged));
public static readonly DependencyProperty ColumnsProperty = DependencyProperty.Register("Columns", typeof(int), typeof(Pager), new PropertyMetadata(1, OnColumnsChanged));
public static readonly DependencyProperty SelectedEntryProperty = DependencyProperty.Register("SelectedEntry", typeof(object), typeof(Pager));

public int Rows
{
get { return (int)GetValue(RowsProperty); }
set { SetValue(RowsProperty, value); }
}

public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}

public object SelectedEntry
{
get { return GetValue(SelectedEntryProperty); }
set { SetValue(SelectedEntryProperty, value); }

}

public ObservableCollection<IPagableEntry> Source
{
get { return (ObservableCollection<IPagableEntry>)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}

public Pager()
{
InitializeComponent();
}

private void ListBoxEntriesOnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedEntry = (sender as ListBox).SelectedItem;
}

private static void OnSourceChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
((PagerViewModel)(pager as Pager).gridPager.DataContext).Collection =
(ObservableCollection<IPagableEntry>)e.NewValue;
}

private static void OnRowsChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
((PagerViewModel)(pager as Pager).gridPager.DataContext).Rows =
(int)e.NewValue;
}

private static void OnColumnsChanged(DependencyObject pager, DependencyPropertyChangedEventArgs e)
{
((PagerViewModel)(pager as Pager).gridPager.DataContext).Columns =
(int)e.NewValue;
}
}

顺便说一句:我不鼓励您在上面使用 as。主要原因是,如果由于某种原因转换失败,那么第一个可见的症状将是一个无用的 NullReferenceException,而不是 InvalidCastException

我建议仅在预期某些时候强制转换失败时才使用as。当然,在这种情况下,您也会始终检查null 结果并适本地处理它。

如果您希望转换总是成功,请使用转换运算符。

关于c# - 如何在代码隐藏中将自定义属性从 View 绑定(bind)到 ViewModel?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33198852/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com