I'm using Galasoft's Light MVVM for my Siverlight project.
I have setup everything as instructed: the ViewModel
is bound to View
's DataContext
;
I have a canvas named inkCanvas
in the View
.
When the ViewModel
gets the updated project data, I need to reference inkCanvas
to create a CanvasRender
instance public CanvasRender(Canvas canvas, ProjectData pdata)
.
The problem is in MVVM, the ViewModel
knows nothing about View
, so how can I reference a control (inkCanvas
) in View
?
P.S. (Edited): The workaround I made is: when I pass the project data to the ViewModel
, I also pass the inkCanvas
from View
's code-behind. hmmm, now my code-behind is not clean.
Answer: 1
In MVVM Pattern, you won't reference a Control directly in ViewModel. In MVVM, all is "binding". You inkCanvas will be binding to a property in your 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)); } } }
And XAML:
<InkCanvas Strokes="{Binding MyStrokes}"/>
Edit :
Maybe the workaround for your case is to use EventToCommand : this allow tobind an UI event to an ICommand directly in XAML ( and use Args to pass a ref to the inkCancas)
<i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=LoadedCommand}" PassEventArgsToCommand="True" /> </i:EventTrigger> </i:Interaction.Triggers>
by : Cybermaxshttp://stackoverflow.com/users/1554201Answer: 2
Per the comments above, one way to do this is to extend Canvas
and keep the reference to CanvasRender
inside that class.
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() { } }
You'd probably want to also make ProjectData
a Dependency Property so that it's bindable.
This allows you to maintain the MVVM pattern, because now you can write in XAML:
<local:MyCanvas ProjectData="{Binding ViewModel.ProjectData}" />
by : dbasemanhttp://stackoverflow.com/users/1001985Answer: 3
If your going to use the EventToCommand approach (which you tried in another answer), then instead of using the PassEventArgsToCommand property use the CommandParameter property and bind it to your Canvas.
<i:Interaction.Triggers> <i:EventTrigger EventName="Loaded"> <cmd:EventToCommand Command="{Binding Path=CanvasLoadedCommand}" CommandParameter="{Binding ElementName=inkCanvas}" /> </i:EventTrigger> </i:Interaction.Triggers>
Then in your 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; }); } }
So as soon as your canvas is loaded, you should then have a reference to it saved in your view model.
by : bugged87http://stackoverflow.com/users/1575237
No comments:
Post a Comment
Send us your comment related to the topic mentioned on the blog