开发者

How to pass the current Instance(sender) of xaml(view) into ViewModel

I need the instance of view in viewmodel to manipulate the element of view from ViewModel. how can I pass the instance of current View (sender) to ViewModel.

<UserControl...>
    <br>...<br>
    <Button x:Name="btnRemove" Width="100" Height="30" 
        Content="Remove" Margin="5" Visibility="Hidden"  
        Command="{Binding CellFrame.WidgetRemoveCommand, Mode=OneWay, Source={StaticResource Locator}}" 
        CommandParameter="{Binding Mode=OneWay}" />
    <br>...<br>
</UserControl>
开发者_StackOverflow中文版

This passes the instance of viewModel in WidgetRemoveCommand. How to pass the Intance of Usercontrol.

Thanks


In order to solve this, when the parent view creates the child view, have it inject a "remove" command into the view model at creation time as below.

//Parent
var model = new ChildControlViewModel();
var view  = new ChildControl(model);
Children.Add(view);
model.RemoveCommand = ()=>Children.Remove(view);

Obviously this is massively simplified, also I'd make sure that you have a view control factory that ties up to a viewmodel, even having this in the code behind seems... wrong to me.

Also, you can use the messenger and register for messages alternatively which IS an acceptable way to notify the view of the view model's action. For instance, I use this to register view->view interactions for a zoom slider in one of my projects. This approach COULD be used for removal.

    public FlickrPhotoBrowserViewModel()
    {
        Photos = new ObservableCollection<FlickrPhotoViewModel>();
        Messenger.Default.Register<ZoomChangedMessage>(this, message => ImageSize = message.Content);
    }

When I create a photo:

    public async Task CreatePhotoContainerAsync(string photoID, IImageSearchService searchService, IStreamService streamService)
    {
        if (photoID != null)
        {
            var Photo = new FlickrPhotoViewModel(photoID);

            Photo.ShowDetailsCommand = new RelayCommand(() =>
            {
                FlickrPhotoDataViewer.ShowPhoto(photoID, searchService, streamService);
            });



            // REMOVE CODE!!! ^_^
            Photo.RemovePhotoCommand= new RelayCommand(() =>
            {
                Photos.Remove(Photo);
                FlickrPhotoDataViewer.CleanupPhotoElement(Photo);
            });
            // REMOVE CODE!!! ^_^


            //update async collection from bound UI thread
            DispatcherHelper.CheckBeginInvokeOnUI(() => Photos.Add(Photo));

            var target = await searchService.GetPhotoThumbnailUriAsync(photoID);

            Photo.ImageStream = await streamService.GetStreamAsync(target);

            Debug.WriteLine("Image Download Complete " + target);
        }
        else
        {
            Debug.WriteLine("Image NULL " + photoID);
        }
    }


In this scenario, you can simply bind the Command property in constructor of user control. Have a locator class which keeps pointer to CellFrame view model.

btnRemove.Command = some_locator_class.static_method.WidgetRemoveCommand;
btnRemove.CommandParameter = this;

The CellFrame view model can have a RelayCommand named WidgetRemoveCommand like below:

RelayCommand<CellFrame> WidgetRemoveCommand 

Now, this relay command has delegate method defined like below:

public void WidgetRemoveAction(CellFrame cell)
{
    // here you get it! 
}

So, the trick is to send the 'this' in command parameter.

Hope this helps.


For example MVVM Light has an option to pass EventArgs with the command. In EventArgs there is sender and from that sender (parent etc) you can search the tree.

But anyway not very good idea to mess with view in viewmodel. I would place the logic in View's code behind, it's just fine.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜