Search code examples
c#wpfmvvmviewmodeldatacontext

In MVVM is it acceptable to access the ViewModel in the view's code behind?


IN an MVVM pattern is it acceptable or even possible to access ViewModel properties in the views code behind?

I have an observable collection which is populated in the ViewModel. I need to use it in the view to bind to an endless ticker with a linked list. i.e.

    private LinkedList<Border> tickerForex = new LinkedList<Border>();

    public ForexBuy()
    {
        InitializeComponent();
        DataContext = new ForexViewModel();
    }

    private void InitializeForexTicker()
    {
        CanvasForexBuyTicker.Children.Clear();
        foreach (var currency in DataContext.Currencies) //Is this possible/allowable???
        {
           AddTickerItem(currency);
        }

        CanvasForexBuyTicker.Dispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate
        { var node = tickerForex.First;

            while (node != null)
            {
                if (node.Previous != null)
                {
                    Canvas.SetLeft(node.Value, Canvas.GetLeft(node.Previous.Value) + node.Previous.Value.ActualWidth + gap);
                }
                else
                {
                    Canvas.SetLeft(node.Value, CanvasForexBuyTicker.Width + gap);
                }

                node = node.Next;
            }

            return null;

        }), null);

}

void AddTickerItem(Currency currency)
    {
        Border border = new Border();
        border.Background = new SolidColorBrush(Color.FromArgb(255, 0, 99, 99));

        if (currency.IsUpward == 0)
        {
            border.Background = new SolidColorBrush(Color.FromArgb(255, 255, 153, 0));
        }

        border.BorderThickness = new Thickness(3);
        border.BorderBrush = new SolidColorBrush(Colors.White);
        border.CornerRadius = new CornerRadius(10);
        border.Width = Double.NaN;
        border.Height = 35;

        UIHelper.CanvasAutoSize canvas = new UIHelper.CanvasAutoSize();
        canvas.Background = Brushes.Green;  
        canvas.Tag = currency;
        canvas.Height = Double.NaN;

        TextBlock tb = new TextBlock
        {
            Text = currency.Code + " " + currency.Sell + " ",
            FontSize = 22,
            FontWeight = FontWeights.Bold,
            Foreground = Brushes.Black
        };

        tb.SetValue(Canvas.LeftProperty, 8d);
        tb.SetValue(Canvas.TopProperty, 2d);
        canvas.Children.Add(tb);

        tb.TouchDown += TouchTickerItem;

        border.Child = canvas;

        CanvasForexBuyTicker.Children.Add(border);
        Canvas.SetTop(CanvasForexBuyTicker, 3);
        Canvas.SetLeft(CanvasForexBuyTicker, 0);

        tickerForex.AddLast(border);
    }

I'm a little lost as to whether the dispatcher should fire from the ViewModel or whether to use it in the views code behind.


Solution

  • If the question is just about how to access the ViewModel from code behind, you could simply cast the DataContext to the proper type:

    var viewModel = (MyViewModel)DataContext;
    
    foreach (var currency in viewModel.Currencies)
    {
        ...
    }
    

    If this is acceptable or not is a matter of taste. I do not see any fundamental difference in accessing the view model by bindings in the view's XAML or by a piece of code-behind.