[英]Call NotifyPropertyChanged from different ViewModel
我在ItemsControl內有一個Canvas設置,使用按鈕進行填充。 每個按鈕都有一個X和Y位置屬性,該屬性用於將按鈕定位在畫布上。
我想做的是使項目位置相對於畫布的大小。 我的問題是,當我調整畫布大小時,ViewModels按鈕沒有得到NotifyPropertyChanged調用,因此它們的位置永遠不會更新。
<ItemsControl ItemsSource="{Binding Buttons}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Top" Value="{Binding PosY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="Canvas.Left" Value="{Binding PosX, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:ToggleButton}">
<local:ToggleButton DataContext="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
在ToggleButtonViewModel中:
public double PosY {
get {
return (_Button.PositionVertical * Size[1]);
}
}
public double PosX {
get { return (_Button.PositionHorizontal * Size[0]); }
}
Size是帶有畫布的X和Y尺寸的double []。 我嘗試將其存儲在CanvasViewModel中,在這種情況下,可以使用畫布上的SizeChanged事件來對其進行更新,但是當尺寸更改時,我無法弄清楚如何在ToggleButtonViewModel中更新PosX和PosY。 我也嘗試將大小作為靜態參數存儲在所有ToggleButtonViewModels中,但是我無法將NotifyPropertyChanged與靜態參數一起使用。
有什么想法可以讓我在畫布大小更改時如何更新PosX和PosY?
我認為這里的方法是實現一個自定義面板,就像Clemens建議的那樣,該面板將覆蓋您的排列邏輯,並為定位添加一些附加的屬性。 我為此做了一個非常快速的小型解決方案,它看起來像您想要的那樣工作。
它是一個簡單的面板“ RelativePositionCanvas ”,提供了兩個附加的屬性“ RelativeX ”和“ RelativeY ”,它們是雙精度值,通常范圍從0到1,用於設置左上角相對於面板尺寸的位置。
如果要添加更多內容,例如將其對齊到右側或使尺寸相對,則只需為其添加一些附加的附加屬性,然后在ArrangeOverride方法中使用它們。
public class RelativePositionCanvas : Panel
{
#region Properties
#region RelativeX
public static readonly DependencyProperty RelativeXProperty =
DependencyProperty.RegisterAttached(
"RelativeX",
typeof(double),
typeof(RelativePositionCanvas),
new FrameworkPropertyMetadata(
0.0d,
new PropertyChangedCallback(OnPositioningChanged)));
public static double GetRelativeX(DependencyObject d)
{
return (double)d.GetValue(RelativeXProperty);
}
public static void SetRelativeX(DependencyObject d, double value)
{
d.SetValue(RelativeXProperty, value);
}
#endregion
#region RelativeY
public static readonly DependencyProperty RelativeYProperty =
DependencyProperty.RegisterAttached(
"RelativeY",
typeof(double),
typeof(RelativePositionCanvas),
new FrameworkPropertyMetadata(
0.0d,
new PropertyChangedCallback(OnPositioningChanged)));
public static double GetRelativeY(DependencyObject d)
{
return (double)d.GetValue(RelativeYProperty);
}
public static void SetRelativeY(DependencyObject d, double value)
{
d.SetValue(RelativeYProperty, value);
}
#endregion
private static void OnPositioningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement uie = d as UIElement;
if (uie != null)
{
RelativePositionCanvas p = VisualTreeHelper.GetParent(uie) as RelativePositionCanvas;
if (p != null)
p.InvalidateArrange();
}
}
#endregion
protected override Size MeasureOverride(Size availableSize)
{
Size childConstraint = new Size(Double.PositiveInfinity, Double.PositiveInfinity);
foreach (UIElement child in InternalChildren)
{
if (child == null) { continue; }
child.Measure(childConstraint);
}
return new Size();
}
protected override Size ArrangeOverride(Size arrangeSize)
{
var children = this.Children;
foreach(UIElement child in children)
{
if (child == null) { continue; }
var childRelativeX = GetRelativeX(child);
var childRelativeY = GetRelativeY(child);
var posX = childRelativeX * arrangeSize.Width;
var posY = childRelativeY * arrangeSize.Height;
child.Arrange(new Rect(new Point(posX, posY), child.DesiredSize));
}
return arrangeSize;
}
}
要使用它,您必須用RelativePositionCanvas替換ItemsPanelTemplate,並用RelativePositionCanvas.RelativeY和RelativePositionCanvas.RelativeX屬性替換Canvas.Top和Canvas.Left屬性,並且應該可以使用
選項1)在ToggleButtonViewModel中,將PosX和PosY的定義更改為“普通” WPF通知屬性(假定您知道我的意思),這些屬性將在更改時通知。 當Size中的值更改時,請在ViewModel上設置屬性。 例如:
_viewModel.PosY = _Button.PositionVertical * Size[1];
_viewModel.PosX = _Button.PositionHorizontal * Size[0];
這樣可以很好地分離關注點。 但可能無法實現,具體取決於您所持有的信息的位置。
Option2)在ViewModel中添加一個方法,您可以調用該方法以指示Size已更改,您可以在其中進行以下操作:
RaiseNotifyPropertyChanged(nameof(PosX));
RaiseNotifyPropertyChanged(nameof(PosY));
(如果需要,我可以為您提供RaiseNotifyPropertyChanged的實現,但這是ViewModel中可能已經包含的非常標准的WPF樣板代碼。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.