Silverlight 如何绕过引用视图';s控件

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

我正在使用Galasoft的Light MVVM进行我的Siverlight项目

我已经按照指示设置了所有内容:
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;
        }); 
    }
}