Silverlight 如何绕过引用视图';s控件
我正在使用Galasoft的Light MVVM进行我的Siverlight项目 我已经按照指示设置了所有内容:Silverlight 如何绕过引用视图';s控件,silverlight,mvvm,view,viewmodel,mvvm-light,Silverlight,Mvvm,View,Viewmodel,Mvvm Light,我正在使用Galasoft的Light MVVM进行我的Siverlight项目 我已经按照指示设置了所有内容:ViewModel绑定到View的DataContext 我在视图中有一个名为inkCanvas的画布 当ViewModel获取更新的项目数据时,我需要引用inkCanvas来创建CanvasRender实例公共CanvasRender(Canvas Canvas,ProjectData pdata) 问题是在MVVM中,视图模型对视图一无所知,因此如何在视图中引用控件(inkCanv
ViewModel
绑定到View
的DataContext
我在视图中有一个名为inkCanvas
的画布
当ViewModel
获取更新的项目数据时,我需要引用inkCanvas
来创建CanvasRender
实例公共CanvasRender(Canvas Canvas,ProjectData pdata)
问题是在MVVM中,视图模型
对视图
一无所知,因此如何在视图
中引用控件(inkCanvas
)
附言(已编辑):我的解决方法是:当我将项目数据传递到视图模型
时,我还将inkCanvas
从视图
的代码传递到后面。嗯,现在我的代码不是干净的。在MVVM模式中,您不会直接在ViewModel中引用控件。在MVVM中,一切都是“绑定”的。inkCanvas将绑定到ViewModel中的属性
public class MyViewModel : INotifyPropertyChanged
{
private readonly StrokeCollection _mystrokes;
public MyViewModel ()
{
_mystrokes= new StrokeCollection();
(_mystrokesas INotifyCollectionChanged).CollectionChanged += delegate
{
//the strokes have changed
};
}
public event PropertyChangedEventHandler PropertyChanged;
public StrokeCollection MyStrokes
{
get
{
return _mystrokes;
}
}
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
和XAML:
<InkCanvas Strokes="{Binding MyStrokes}"/>
编辑:
可能您的案例的解决方法是使用EventToCommand:这允许将UI事件直接绑定到XAML中的ICommand(并使用Args将引用传递给inkCancas)
根据上面的注释,一种方法是扩展Canvas
并将对CanvasRender
的引用保留在该类中
public class MyCanvas : Canvas
{
private CanvasRender _canvasRender;
private ProjectData _data;
public ProjectData Data
{
get { return _data; }
set
{
_data = value;
_canvasRender = new CanvasRender(this, _data);
}
}
public MyCanvas() : base()
{
}
}
您可能还希望将ProjectData
设置为一个依赖属性,以便它可以绑定
这允许您维护MVVM模式,因为现在您可以用XAML编写:
<local:MyCanvas ProjectData="{Binding ViewModel.ProjectData}" />
如果您打算使用EventToCommand方法(您在另一个答案中尝试了该方法),则不要使用PassEventArgsToCommand属性,而是使用CommandParameter属性并将其绑定到画布
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmd:EventToCommand Command="{Binding Path=CanvasLoadedCommand}"
CommandParameter="{Binding ElementName=inkCanvas}" />
</i:EventTrigger>
</i:Interaction.Triggers>
然后在ViewModel中:
public class ViewModel
{
private Canvas m_canvas;
public RelayCommand<Canvas> CanvasLoadedCommand { get; private set; }
public ViewModel()
{
CanvasLoadedCommand = new RelayCommand<Canvas>(canvas =>
{
m_canvas = canvas;
});
}
}
公共类视图模型
{
私人帆布m_帆布;
public RelayCommand CanvasLoadedCommand{get;private set;}
公共视图模型()
{
canvasloaddedcommand=newrelaycommand(canvas=>
{
m_canvas=画布;
});
}
}
因此,一旦加载画布,就应该在视图模型中保存对画布的引用。理想情况下,不必从视图模型中引用特定视图,事实上应该避免引用。我可以确切地问一下,您打算对视图模型中的画布做什么吗?@KodeKreachor,我需要在我的CanvasRender
类库中使用它。您打算对CanvasRender方法中的画布做什么?@KodeKreachor,将所有项目数据渲染到画布,而CanvasRender
来自另一个类库。@Peterle我突然想到,你可以接受Cybermaxs的建议,只使用绑定,但扩展Canvas
并将所有渲染代码放在扩展中。根据需要向画布扩展添加新的依赖项属性。感谢您的回复。但是,正如我非常清楚地指出的那样,我的CanvasRender
要求我传递Canvas
参数,而不是inkCanvas
的属性,您能否让我更清楚一些?在哪里传递inkCanvas
?为了调用它,我必须定义一个事件??您可以将inkCanvas的每个事件(已加载、KeyUp、MouseDown…)绑定到带有args的自定义命令。使用PassEventArgsToCommand=True,我认为可以将RoutedEventArgs(和发送方)传递给视图模型中的自定义命令。我没有时间来测试这一点,但我认为道路是畅通的……不幸的是,e.OriginalSource
在触发加载的事件时总是空的。public RelayCommand canvasloadded命令{get{返回新的RelayCommand((e)=>{theCanvas=e.OriginalSource as InkPresenter;});}@peter您可能应该使用CommandParameter属性而不是PassEventArgsToCommand属性。看看我的答案。谢谢你的回复。我会尽快试用,并让您知道它是如何工作的。我扩展了画布,但现在我有了新的问题,如何在MyCanvas
中获取CanvasRender
。我需要公开另一个名为CanvasRender
?@PeterLee的属性,我真的不知道。。。我想您应该在扩展画布中实例化CanvasRender
。您是说需要将其作为XAML属性绑定到扩展画布吗?
public class ViewModel
{
private Canvas m_canvas;
public RelayCommand<Canvas> CanvasLoadedCommand { get; private set; }
public ViewModel()
{
CanvasLoadedCommand = new RelayCommand<Canvas>(canvas =>
{
m_canvas = canvas;
});
}
}