Reputation: 2435
I'm writing a 3D modelling program in WPF and Prism using the MVVM format.
I'm using canvases to show the different views (top, front, side) with grid lines. I want the user to be able to adjust the spacing between lines, and I have a TextBox that holds the value, which is bound to a property in the view-model. This parts works fine.
To draw the grid lines using the user's spacing, however, I need to access that property from the View, where the lines are being drawn (in MainWindow.xaml.cs). I still need it to exist in the view-model as well, though, for certain functionality to work (like snap-to-grid).
I foresee that there will be many properties I'll need to bounce back and forth, since the UI and the functionality will be working closely together in a program like this.
The way I've gotten around this problem in the past is by first creating an invisible label in the UI. Then I use a function to set the label's binding dynamically and grab the value from the label.
public int TempIntBind(string bind)
{
DummyLabel.SetBinding(Label.ContentProperty, new Binding(bind));
int newInt;
if (DummyLabel.Content != null && int.TryParse(DummyLabel.Content.ToString(), out newInt))
{
return newInt;
}
else
{
return -1;
}
}
This works, but it seems rather hacky and also circumvents the MVVM pattern.
Is there a better way to achieve this result?
Since:
this.DataContext = new View_Model ();
I was hoping I could just say something like:
x = this.DataContext.gridsize;
But apparently that's not how that works. Too JavaScript-y, I suppose.
Here are the relevant bits of my main window xaml:
<Window x:Class="Brick.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Brick"
mc:Ignorable="d"
Title="Brick" Width="800" Height="600">
<WrapPanel Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1" Margin="5">
<Label>Grid Size</Label>
<TextBox Width="50" Height="20" Text="{Binding Path=grid_size, UpdateSourceTrigger=PropertyChanged}" />
</WrapPanel>
<Canvas Grid.Column="1" Grid.Row="2" x:Name="top_view" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,5,5" Background="Black"></Canvas>
</Grid>
</Window>
The View:
namespace Brick
{
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent ();
this.DataContext = new View_Model ();
draw_grid_lines ();
}
void draw_grid_lines ()
{
int spaces = grid_size; // <-- Right here is the problem spot
}
}
}
And the View-Model:
namespace Brick
{
class View_Model : Prism.Mvvm.BindableBase
{
public event PropertyChangedEventHandler property_changed_event;
private int grid_size_private;
public int grid_size
{
get {return grid_size_private;}
set
{
if (grid_size_private != value)
{
grid_size_private = value;
RaisePropertyChanged ("grid_size");
}
}
}
public View_Model ()
{
grid_size = 8;
}
}
}
Upvotes: 1
Views: 3664
Reputation: 145
did you try casting the DataContext to View_Model in code behind?
namespace Brick
{
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent ();
this.DataContext = new View_Model ();
draw_grid_lines ();
}
void draw_grid_lines ()
{
var vm = (View_Model)this.DataContext;
int spaces = vm.grid_size; // <-- Right here is the problem spot
}
}
}
Upvotes: 2
Reputation: 16652
You can assign a property to DataContext
and just access members through it:
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
Model = new Model();
DataContext = Model;
}
private Model Model { get; }
private void Whatever()
{
var value = Model.Value;
}
}
internal class Model
{
public int Value { get; set; }
}
}
For the syntax issue you were running into you would have done:
var x = ((Model) DataContext).Value;
Upvotes: 0