I am Trying to use the new RadSyntaxEditor from Telerik by following this guide.
This is the code I created:
private RadSyntaxEditor _syntaxEditor;
public RadSyntaxEditor SyntaxEditor
{
get => _syntaxEditor;
set
{
if (Equals(value, _syntaxEditor)) return;
_syntaxEditor = value;
OnPropertyChanged();
}
}
public CodeEditorViewModel()
{
SyntaxEditor = new RadSyntaxEditor();
}
public void Test()
{
using (StreamReader reader = new StreamReader("../../ViewModels/ShellViewModel.cs", Encoding.UTF8))
{
SyntaxEditor.Document = new TextDocument(reader);
}
var cSharpTagger = new CSharpTagger(SyntaxEditor);
SyntaxEditor.TaggersRegistry.RegisterTagger(cSharpTagger);
}
my xaml file:
<UserControl x:Class="CodeEditorControl.Views.CodeEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Test" Grid.Row="0">Test</Button>
<telerik:RadSyntaxEditor x:Name="SyntaxEditor" Grid.Row="1"/>
</Grid>
</UserControl>
The control is showing without a problem and is responding to input etc.
But neihter does the document load, nor is there any syntax highlighting.
The Reader loads correct and ReadToEnd() outputs the correct text (ShellViewModel is just a standard cs file with 36 lines).
I am using caliburn.micro and the MVVM design.
Edit: I set up a project with the same template but using code behind instead of binding. This works as intended. So the problem lies within the binding from caliburn.micro and telerik.
Any help is appreciated.
I've noticed that the property in CodeEditorViewModel is of type RadSyntaxEditor and the corresponding UI element is also RadSytanxEditor. Note that this produces a binding error in the Output pane of Visual Studio. I think that the Caliburn.Micro binding engine cannot create this type of relation and currently there are two separate instances of RadSyntaxEditor. The one defined in XAML and the other one defined in the view model. The document is loaded to the one defined in code, but because it is never used in the UI, there is nothing in the application.
To resolve this you can research the Caliburn.Micro framework and more specifically, how to use the naming conventions to data bind the model property to a corresponding property of the UI element. I think the current binding (via the convention) defaults to the Visibility property of RadSyntaxEditor.
Or you can simply use an explicit data binding like this:
<Button x:Name="Test" Grid.Row="0">Test</Button>
<ContentControl Content="{Binding SyntaxEditor}" Grid.Row="1"/>
Note that I've replaced the RadSyntaxEditor control with a ContentControl.
Related
This question already has answers here:
What is DataContext for?
(4 answers)
Closed 4 months ago.
sorry about this question. I know MVVM exist for many years but each time I try to code something with it I face the same issue again and again ans I'm still looking for a real good tutorial about this.
Let's consider we have a main window (MainWindow.xaml) with its view model (MainViewModel.cs).
This window has a grid, in my grid I define 2 user controls. Whatever it is. One is on the left, one on the right. On my main window I have create, in MainViewModel.cs an engine:
internal class MainWindowViewModel
{
public MainWindowViewModel()
{
QCEngine qcEngine = new();
}
}
This engine is my unique model and contains a complex code that read data. Whatever. This engine has a public list of value. I want to display these values on my left and right panels in different ways. Again whatever. The display is not my issue.
My issue is how I pass this list or the entire engine reference to my panels? I'm really lost. I can do this in few seconds with any classic WinForms but I never figure out how to do in MVVM. I'm at this moment where I give up MVVM to do classic WinForms. This time I want to understand.
Can you help me?
My QC engine is a RFID reader. It already works fine as console application. All parameters are in a config file. the idea of the interface is to give more flexibility to the reader. Having a nice result screen, a setting screen, some interactions.
<Window x:Class="Beper.QCTable.Control.View.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:view="clr-namespace:Beper.QCTable.Control.View"
xmlns:viewmodel="clr-namespace:Beper.QCTable.Control.ViewModel"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Window.DataContext>
<viewmodel:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Menu -->
<Menu Grid.Row="0" FontSize="20">
<MenuItem Header="_Menu">
<MenuItem Header="_Advanced"/>
</MenuItem>
</Menu>
<!--Header-->
<StackPanel Grid.Row="1" Background="Orange">
<TextBlock FontSize="20">
Header
</TextBlock>
</StackPanel>
<!--Body-->
<Grid Grid.Row="2">
<view:TabPanel/>
</Grid>
<!--Status Bar-->
<StatusBar Grid.Row="3" FontSize="20">
<StatusBarItem>
Status
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Focus on tab panel:
public class TabPanelViewModel
{
public ObservableCollection<TabItem> Tabs { get; set; } = new ObservableCollection<TabItem>();
public TabPanelViewModel()
{
Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
}
}
I cannot chare the engine code but, really, it is just a list of keys (RFID keys / EPC). This is the only public data. I want to display this list of key by group under my tabs.
Passing "this list or the entire engine reference" to the view defats the purpose of implementing the MVVM design pattern in the first place.
What you should do is to use the engine to prepare and set the state of your app/view in your view model.
The controls in the views should then bind to properties of the view model that contains, and effetively defines, the current state.
I am beginner and have an issue in setting a WPF project and following MVVM pattern; I do not see how to link the view to the viewmodel with the organization below :
I have set 3 folders : Model, View and ViewModel, both at the root of the project named "Company.App.UI".
The App.xaml and MainWindow.xaml are at the root of the project.
Starting with this, I want control the content displayed in the client area of the MainWindow by :
- having the rendered views in the folder 'View' as UserControls, for example 'LoginView.xaml'
- having the corresponding view model in the folder 'ViewModel', for example 'LoginView.xaml.cs'
Then what I did in MainWindow.xaml is :
<Window x:Class="Company.App.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewmodel="clr-namespace:Company.App.UI.ViewModel"
xmlns:view="clr-namespace:Company.App.UI.View" <!-- does not work, not a namespace -->
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type viewmodel:LoginViewModel}">
<view:LoginView/> <!-- does not work -->
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<ContentControl Content="{Binding ClientArea}"/>
</StackPanel>
</Grid>
</Window>
And in MainWindow.xaml.cs :
using System.Windows;
using System.Windows.Controls;
using Company.App.UI.ViewModel;
namespace Company.App.UI
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private UserControl _ClientArea = null;
public UserControl ClientArea
{
get { return _ClientArea; }
set { _ClientArea = value; }
}
public MainWindow()
{
if (_ClientArea == null) { ClientArea = new LoginViewModel(); }
InitializeComponent();
}
}
}
The LoginView is a simple UserControl with one Label just to see it is what it is.
If I put my LoginView.xaml at the root of the project, next to MainWindow.xaml, it works ...
What am I doing wrong / missing ?
I do not want to use any frameworks (PRISM and so on) for getting this to work.
My apologies if my post is a duplicate but I have also fail to find it while searching.
Thanks,
Update
I use VS2013 with 0 updates / patches / etc.
Everything is in the same project.
The errors output is :
The type or namespace name 'View' does not exist in the
namespace 'Company.App.UI' (are you missing an assembly reference?)
The name "LoginView" does not exist in the namespace
"clr-namespace:Company.App.UI.View".
The type 'view:LoginView' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built.
LoginView.xaml :
<UserControl x:Class="Company.App.UI.ViewModel.LoginViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Label>User control login</Label>
</Grid>
</UserControl>
LoginViewModel.cs :
using System.Windows.Controls;
namespace Company.App.UI.ViewModel
{
public partial class LoginViewModel : UserControl
{
public LoginViewModel()
{
}
}
}
In LoginView.xaml change this:
x:Class="Company.App.UI.ViewModel.LoginViewModel"
to this
x:Class="Company.App.UI.ViewModel.LoginView"
because this is a control not a ViewModel
Also, this is how the LoginView.xaml.cs should look like (didn't see your implementation):
using System.Windows.Controls;
namespace Company.App.UI.View
{
/// <summary>
/// Interaction logic for LoginView.xaml
/// </summary>
public partial class LoginView : UserControl
{
public LoginView()
{
InitializeComponent();
}
}
}
when you will get the hang of it (mvvm) I would recommend using the mvvm light toolkit for the plumbing (there is no need to reinvent the wheel)
Exactly .... Do whatever changes Igor has told you .
along with that ,
Change your MainWindow.xaml.cs
if (_ClientArea == null) { ClientArea = new LoginViewModel(); }
to
if (_ClientArea == null) { ClientArea = new LoginView(); }
Also as per my understanding you just want to display one lable from user control to main window and want to study MVVM concept. So here is the explaination for your example which may help you
<Grid>
<!--connect to viewmodel-->
<Grid.DataContext>
<viewmodel:LoginViewModel></viewmodel:LoginViewModel>
</Grid.DataContext>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!--import user control-->
<view:LoginView Grid.Row="0"></view:LoginView>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<ContentControl Content="{Binding ClientArea}"/>
</StackPanel>
</Grid>
Note - Try to keep zero code in any of code behind . Thats the main
purpose of MVVM . It should just have
Model ...(class file which should have purely just proprties )
View ...(usercontrols, xaml,window file which should contain just
xaml code with zero code behind)
Modelview... (class file which should contain purely connection
between view and model, which should not contain any object of
view or model.It connects through the binding)
also i dont know for what purpose you created 'ClientArea' ... Did you define its content somewhere?
Let me know if you need any help... I have some sample demo projects on MVVM.
Post with similar purpose that also helped me to get things :
Binding a ContentControl to UserControl, and reuse same instance,
with the excellent topic within here : How to preserve the full state of the View when navigating between Views in an MVVM application?.
Another good point to start I found after I post my question (...) : https://msdn.microsoft.com/en-us/library/gg405484(v=pandp.40).aspx
Basically what I want to achieve is to manage the content area within one single window and whithout any framework and more precisely manage "transactions", that is switching from one screen to another upon user interaction.
Thanks for all the comments, things are getting clearer.
I am new at MVVM. Currently all my code is written in .cs file which linked to XAML. I want switch to MVVM but experiencing difficulties. I will try to explain why:
I have many different Chart controls and input data specified in .cs file in the way that I am accessing Chart object directly and using it's properties programaticaly to add points for my chart.
Example:
foreach (var group in qcv.Groups)
{
AreaSeries areaSeries = new AreaSeries();
areaSeries.CombineMode = Telerik.Charting.ChartSeriesCombineMode.Stack;
areaSeries.ValueBinding = new PropertyNameDataPointBinding("Rev");
areaSeries.CategoryBinding = new PropertyNameDataPointBinding("Date");
areaSeries.ItemsSource = group as IEnumerable;
RadChart1.Series.Add(areaSeries);
}
But as long as I switch to MVVM RadChart1 objects gets inaccessible in ViewModel file. How can I make it visible in ViewModel class or maybe you can suggest better approach how I can get that object and provide input for my chart without changing my code behind?
My XAML File:
<UserControl x:Class="FrontEnd.RevenueChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:FrontEnd"
mc:Ignorable="d" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" HorizontalAlignment="Stretch" >
<UserControl.DataContext>
<local:RevenueChartViewModel/>
</UserControl.DataContext>
<Grid>
<telerik:RadCartesianChart HorizontalAlignment="Stretch" x:Name="RadChart1" Palette="Metro" Zoom="10,1">
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:CategoricalAxis/>
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis/>
</telerik:RadCartesianChart.VerticalAxis>
<telerik:RadCartesianChart.Behaviors>
<telerik:ChartPanAndZoomBehavior ZoomMode="Both">
</telerik:ChartPanAndZoomBehavior>
</telerik:RadCartesianChart.Behaviors>
</telerik:RadCartesianChart>
</Grid>
</UserControl>
Accessing view controls from the viewmodel is a big no-no in MVVM land. You have to invert your thinking: instead of adding stuff to Series, bind Series to stuff. Use SeriesMappings to get the chart control to convert your groups to series. Here's a bit of off-the-cuff code to get you started:
<telerik:RadCartesianChart HorizontalAlignment="Stretch"
Palette="Metro" Zoom="10,1"
Series="{Binding Groups}"><!-- <=== this is the important part -->
<telerik:RadChart.SeriesMappings>
<telerikCharting:SeriesMapping LegendLabel="Product Sales">
<telerikCharting:SeriesMapping.SeriesDefinition>
<telerikCharting:AreaSeriesDefinition/>
</telerikCharting:SeriesMapping.SeriesDefinition>
<telerikCharting:SeriesMapping.ItemMappings>
<telerikCharting:ItemMapping DataPointMember="XCategory" FieldName="Date"/>
<telerikCharting:ItemMapping DataPointMember="YValue" FieldName="Rev"/>
</telerikCharting:SeriesMapping.ItemMappings>
</telerikCharting:SeriesMapping>
</telerik:RadChart.SeriesMappings>
...
I'm using wpf and c# with the Third party DevExpress Libraries. I'm having a problem with DXCharts. I've tried a few different things to clear or update the chart to no avail. I'm Data-binding to a Data-table(built on the fly) with a dependency property for the Data-source.
The dependency properties for the chart do not seem to be overridden when new data is set to the backing property. This gives me overlaying points on the chart. As you can see in the examples below.
1st Set of Data
2nd Set of Data
I also tried creating new instances of the Chart control and its still showing the old binded dependency properties. The DXchart usercontrol is embedded into a Content Control. I bind the Chart via a content property. All of this is nested under a DevExpress tab control.
Here is some of the code below:
Dependency Properties
public static readonly DependencyProperty DataTableChartProperty = DependencyProperty.Register
("DataTableChart", typeof(DataTable), typeof(MainWindowViewModel));
public static readonly DependencyProperty ContentElementProperty = DependencyProperty.Register
("ContentElement", typeof(FrameworkElement), typeof(MainWindowViewModel));
Backing Properties
public DataTable DataTableChart
{
get { return (DataTable)this.GetValue(DataTableChartProperty); }
set { this.SetValue(DataTableChartProperty, value); }
public FrameworkElement ContentElement
{
get { return (FrameworkElement)this.GetValue(ContentElementProperty); }
set { this.SetValue(ContentElementProperty, value); }
}
UserControl
<UserControl x:Class="Reporting_DIMS.UI.ChartControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts"
xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="1100">
<Grid>
<Border Padding="3">
<dxc:ChartControl Margin="0" Name="chartControl" DataSource="{Binding DataTableChart}">
<dxc:ChartControl.Diagram>
<dxc:XYDiagram2D SeriesDataMember="DIMS User">
<dxc:XYDiagram2D.SeriesTemplate>
<dxc:BarSideBySideSeries2D ValueDataMember="Count" ArgumentDataMember="Entry DateTime" />
</dxc:XYDiagram2D.SeriesTemplate>
</dxc:XYDiagram2D>
</dxc:ChartControl.Diagram>
<dxc:ChartControl.Legend>
<dxc:Legend x:Name="legend"/>
</dxc:ChartControl.Legend>
</dxc:ChartControl>
</Border>
</Grid>
Small MainWindow Portion
<dx:DXTabItem Header="Log Charts" Name="dXTabItem2">
<ContentControl x:Name="contentControl" Content="{Binding ContentElement}"/>
</dx:DXTabItem>
If anyone has any ideas, I would greatly appreciate it. Thanks in Advance!
rreeves is correct. A simple workaround for me was to wrap my DXChartControl in a 2nd ContentControl. Instead of binding directly to the ChartControl, let an inner ContentControl hand the binding to the ChartControl, that way,when the content is changed, the ContentControl generates a new instance via the ContentTemplate.
<DataTemplate x:Key="chartTemplate">
<dex:ChartControl DataSource="{Binding}" DataContextChanged="chartControl_DataContextChanged_1"/>
</DataTemplate>
<ContentControl Grid.Row="1" ContentTemplate="{StaticResource ResourceKey=chartTemplate}" Content="{Binding 'YOUR ITEMSSOURCE'}"/>
Then you can rebuil the Chart in the DataContextChanged.
Hope this helps!
I ended up removing the old charting object and creating a new one. This is the intended behavior of the Charts per DevExpress.
By default when you use "ActivateItem(new Control());" your control is loaded into a ContentControl which with the name ActiveItem, fro example. . If I have multiple content controls on my page how would I load controls into them whilst retaining the ability to use the default functionality of being able to load controls into the the active item control.
for example I want to have a login control to be loaded into the Login ContentControl, and when a user successfully login I want a new control to be loaded into the ActiveItem ContentControl.
Thanx in advance.
If the ViewModel that gets binded to the UI contains a property with the name that matches a content control. The Content control view automatically gets resolved the the view supported by this property, provided this property itself is a ViewModel type and has been registed with Ioc container. For example
<ContentControl x:Name="LoginStatus"></ContentControl>
If there is a property LoginStatus on the main ViewModel (LoginStatus property itself is a ViewModel). The content control would correctly get rendered with the appropriate view.
This is an old question, but in case anyone is having the same issue, here is my solution:
Your main window that contain both (or even more than two) of your User Controls must be inherited from Caliburn.Micro.Conductor<Screen>.Collection.AllActive;
Your User Controls must be inherited from Caliburn.Micro.Screen;
You must also keep naming conventions in mind. If you use MenuUC as the name of a ContentControl in your View, also create a property named MenuUC in your ViewModel;
Initialize your UserControl as I do in Constructor;
Now you can use ActivateItem(MenuUC) and DeactivateItem(MenuUC) everywhere in your code. Caliburn.Micro automatically detects which one you want to work with.
Example XAML View code:
<Window x:Class="YourProject.Views.YourView"
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"
mc:Ignorable="d"
Title="YourViewTitle" Width="900" Height="480">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="4*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Menu Side Bar -->
<ContentControl Grid.Row="0" Grid.Column="0" x:Name="MenuUC" />
<!-- Panel -->
<Border Grid.Column="1" Grid.RowSpan="2" BorderThickness="1,0,0,0" BorderBrush="#FF707070" >
<ContentControl x:Name="PanelUC" />
</Border>
</Grid>
</Window>
Example C# ViewModel code:
class YourViewModel : Conductor<Screen>.Collection.AllActive
{
// Menu Side Bar
private MenuUCViewModel _menuUC;
public MenuUCViewModel MenuUC
{
get { return _menuUC; }
set { _menuUC = value; NotifyOfPropertyChange(() => MenuUC); }
}
// Panel
private Screen _panelUC;
public Screen PanelUC
{
get { return _panelUC; }
set { _panelUC = value; NotifyOfPropertyChange(() => PanelUC); }
}
// Constructor
public YourViewModel()
{
MenuUC = new MenuUCViewModel();
ActivateItem(MenuUC);
PanelUC = new FirstPanelUCViewModel();
ActivateItem(PanelUC);
}
// Some method that changes PanelUC (previously FirstPanelUCViewModel) to SecondPanelUCViewModel
public void ChangePanels()
{
DeactivateItem(PanelUC);
PanelUC = new SecondPanelUCViewModel();
ActivateItem(PanelUC);
}
}
In the above example, ChangePanels() acts as a method to load new User Control into your ContentControl.
Also read this question, it might be help you further.
You should have a look at Screen Conductors. See here.