WPF: Cannot resolve symbols in code behind - c#

Hi I'm trying to learn a bit of WPF and C# for a project I'm working on. I realised after working for a while that I was going to use couple of the same item and I thought it would be fitting to create my own class to make it easier to use. However now I can't reference elements defined in the XAML in the code behind like I could when just doing it in a window. The error I get is "Cannot resolve symbol 'ThaButton" in the ContactPanel.xaml.cs:
using System.Windows.Controls;
namespace WPF_OOM
{
public partial class ContactPanel : ContentControl
{
public Contact Person { get; set; }
public ContactPanel()
{
ThaButton.Content = "test";
}
}
}
My ContactPanel.xaml
<UserControl x:Class="WPF_OOM.ContactPanel:UserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel x:Name="dp">
<TextBlock x:Name="NameTextBlock" Text="testtesttest" DockPanel.Dock="Left"></TextBlock>
<Button x:Name="ThaButton" Content="button" DockPanel.Dock="Right"></Button>
</DockPanel>
</UserControl>
Hopefully I've explained my problem well enough. I might have taken the wrong approach to this problem, let me know if there's a better way.
Cheers

Remove :UserControl from x:Class="WPF_OOM.ContactPanel:UserControl" so it looks like x:Class="WPF_OOM.ContactPanel"
Also in your code behind you have the ContactPanel inheriting form ContentControl, but in your xaml it inherits from UserControl. These base classes must match. So change them both to be UserControl or ContentControl
It looks like you created a separate .cs file? I would recommend working with the code behind generated with the xaml file. One way to get to it is in the xaml editor right-click and choose 'View code'. If you imported the xaml and .cs file then reloading the project or restarting visual studio should combine them again in solution explorer if they are not already.
I would suggest looking into the Model-View-ViewModel or MVVM pattern. It works rather nice with WPF ;)
Hope this helps get you started.

Related

writing a VTK aplication in WPF, trying to follow MVVM

So I'm pretty new to WPF and MVVM, and while I understand the premise, a lot of this stuff is like trying to read hieroglyphs for me.
Basically, my situation is this: I'm using Activiz, a c# wrapper for VTK, which is an image processing/visualization library. So, in this library, there's a WinForms control called vtk:RenderWindowControl, which is an opengl control containing the class that handles all of the visualization functionality. I think it'd be easier to just use WinForms, but that's not really an option for me.
So, to use vtk:RenderWindowControl in a WPF application, I just need to shove it into a WindowsFormsHost and then I can use it more or less just like the example code, in the code behind (if that's the correct term for the .xaml.cs file)
That's fine for a test app, but in practice, I'd like to follow MVVM if possible. This is where I've run into a wall. If "renderControl" lives in the View class, how can I reference it and use it from the ViewModel? I think binding is the answer to that question, but I only really know how to do that for simple types and commands.
Following ideas in another thread I found, I managed to set up something like this answer
My codebehind looks like this:
public partial class RenderPanel_View : UserControl
{
public static readonly new DependencyProperty RWControlProperty =
DependencyProperty.Register("RWControl", typeof(RenderWindowControl), typeof(RenderPanel_View), new PropertyMetadata(null));
public RenderWindowControl RWControl
{
get { return (RenderWindowControl)GetValue(RWControlProperty); }
set { SetValue(RWControlProperty, value); }
}
public RenderPanel_View()
{
// This is necessary to stop the rendercontrolwindow from trying to load in the
// designer, and crashing the Visual Studio.
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) {
this.Height = 300;
this.Width = 300;
return;
}
InitializeComponent();
this.RWControl = new RenderWindowControl();
this.RWControl.Dock = System.Windows.Forms.DockStyle.Fill;
this.WFHost.Child = this.RWControl;
}
}
My .xaml looks like this
<UserControl x:Class="vtkMVVMTest.RenderPanel.RenderPanel_View"
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:vtk="clr-namespace:Kitware.VTK;assembly=Kitware.VTK"
xmlns:rp="clr-namespace:vtkMVVMTest.RenderPanel"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
RWControl="{Binding VMControlProperty}">
<Grid>
<WindowsFormsHost x:Name ="WFHost"/>
</Grid>
</UserControl>
So two things. One, That last line of the xaml header is an error, "The member 'RWControl' is not recognized or accessible". I don't really understand why. Second, for what I'm guessing is the ViewModel half of the equation, how is VMControlProperty supposed to be defined?
Am I at least on the right track here, or is this way off base?
Some controls are not MVVM friendly and you have make the ViewModel aware of View interface and allow interact with it directly. Do not open the whole control to the ViewModel it will ruin the ability to write tests, put an interface on top for example IRenderPanelView and open in the interface only the functionality you need to access from ViewModel. You can then create a DP property of this type in the view, set it in the constructor and bind it to ViewModel.View property in xaml.

How do I reconnect a XAML view file with it's code behind file?

I find very frequently that while I'm 'prototyping', and I change the base type of the code behind class, or something like that, that the two files become completely unaware of each other. Example:
XAML:
<UserControl x:Class="G4S.XTime.Modules.Employees.Details.Views.EmployeeGridView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
...
Code-behind:
namespace G4S.XTime.Modules.Employees.Details.Views
{
public sealed partial class EmployeeGridView: UserControl
{
public EmployeeGridView()
{
//InitializeComponent();
}
}
}
The call InitializeComponent produces a compile time error, saying it doesn't exist.
This disconnect phenomenon happens often enough to be costing me time, and I often just copy the code out of both files, delete the view, add a new view with the same name, paste the same code back, and everything works.
What am I missing that connects the two files? In the project file, I see the code-behind depends on the XAML, so I think if I comment out InitializeComponent, then compile with only the XAML, I will have the other part of my code-behind partial class. But this does not work. It doesn't seem to compile the XAML at all unless there is a code behind.
What can I do to reconnect these two files, in most cases?
Edit your project file and make sure you have something similar to this:
<Compile Include="EmployeeGridView.xaml.cs">
<DependentUpon>EmployeeGridView.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
For me the problem was caused by not having the correct way of including the files in the csproj file.
incorrect:
<CodeAnalysisDictionary Include="Windows\ConnectionSecuritySettings.xaml">
correct:
<Page Include="Windows\ConnectionSecuritySettings.xaml">
This happened when I moved the items to a new project
Make sure the declaration at the top of the xaml matches the code behind file with the full path including namespace.
eg. If namespace name is "MyControls" and Code behind Class is "MyNewControl" then
xaml declaration should be something like ..
<UserControl x:Class="MyControls.MyNewControl"
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"
mc:Ignorable="d"
Height="41" Width="77"
>
and code behind would be ..
namespace MyControls
{
/// <summary>
/// Interaction logic for MyNewControl.xaml
/// </summary>
public partial class MyNewControl: UserControl
{
#region Constructors
public MyNewControl()
{
InitializeComponent();
}
#endregion
}
}
I had the same problem (InitializeComponent could not be found) after a cut-paste of my XAML. The answer suggested here solved my problem. The suggestions is, in the Properties window of the XAML, change the Build Action to Page. Apparently the copy-paste can change the Build Action to Resource.
Hope this helps!
[Edit] I just wanted to add that this was also after updating the namespace for both the code-behind and in the xaml:
x:Class="NewNamespace.CodeBehindClass"

How do you set the conent of a Silverlight element to a view?

I am updating some xaml I have written to instead use the code behind due to an issue cropping up.
Pane refers to a Telerik RadPane object.
What I need to do semantically is :
pane.Content = PaneView.xaml;
PaneView being a xaml file containing multiple elements and info. This will not work.
I had this working as follows in the previous xaml file, so it is possible to do; though I don't know how. Can anyone help ?
<UserControl x:vws="MyProject.ViewFolder.Views">
...
<telerik:RadPane Header="PaneView" CanUserClose="False" CanFloat="False"
telerik:RadDocking.SerializationTag="PaneView">
<vws:PaneView />
</telerik:RadPane>
What wrapper do I need to put my xaml file in to force this to work?
Thanks very much
If your RadPane control (the XAML) is defined as x:Class="SomeNameSpaceHere.PaneView" you can set the content pretty simply via:
pane.Content = new PaneView();
You can use a simple UserControl as a container:
<UserControl x:Class="SomeNameSpaceHere.PaneView">
...
</UserControl>

Design pattern in WPF

I am making my first WPF application, so this question may seem rather odd. I have been reading about MVVM and so far it has made sense to me. What I don't understand, though, is separating all the XAML.
What I mean is this: I assume you don't place everything in the MainWindow.xaml and just collapse controls based upon what is going to be used. I would think you would want a container that would contain xaml of other files. Is this correct?
How do you go about separating the XAML out so that it isn't just a mash of everything in one file?
How do you go about separating the XAML out so that it isn't just a mash of everything in one file?
There are many ways, including creating a seperate UserControl, CustomControl, Page or Window
For example, if you wanted to pull some XAML out of your MainWindow.xaml, you could create a UserControl (right-click project, Add, New Item..., User Control (WPF)) called MyUserControl.xaml like this:
<UserControl x:Class="WpfApplication1.MyUserControl"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
<TextBlock>This is from a different XAML file.</TextBlock>
</Grid>
</UserControl>
and then use this control in your MainWindow.xaml like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myControls="clr-namespace:WpfApplication1">
<Grid>
<myControls:MyUserControl/>
</Grid>
</Window>
Note that you need to add a reference to the namespace of your UserControl
xmlns:myControls="clr-namespace:WpfApplication1"
I agree with Kevin's answer about UserControl and Window, so I'll just address the follow up question:
So I should switch between various controls that are collapsed/visible in the content of my MainWindow when the user is interacting with my application?
That is a valid option. It might get messy if you are working with a large application.
The other options that I've used are
switching Views in the code behind; i.e. on the click events you can add and remove elements from the page as you would have done in WinForms. This is not pure MVVM and some people will jump down your throat, but I believe MVVM is a tool, not a religion.
provide Views as properties in your ViewModel, and bind to them from your parent View. I don't know if this is pure MVVM, it's nice when you need to dynamically create Views depending on complex conditions but it can get complicated
use DataTemplates, which are essentially rules to determine the View to use based on the type of data that is provided. So if the data is an Address (or AddressViewModel), use the AddressView. If the data is a CustomerViewModel, use the CustomerView. And so on.
DataTemplates are the preferred pattern in my opinion - clean, easy to maintain, and a nice standard. It's trivial to go to the DataTemplate to see how the binding works, whereas the other two options I've given may lead to spaghetti code in the wrong hands.
MSDN has a nice page on DataTemplates in WPF.
When using Caliburn framework you could compose your application using smaller Views and ViewModels and have a shell which binds all those smaller views together. The shell would display one or many views at the same time, depending on how you want your application to behave. The good thing about this - unlike the pattern mentioned above where you hardcode the name of the View/UserControl in other places - is that you just create a ContentControl and bind it to the correct ViewModel property and Caliburn will find the correct View for you by convention.
Let's say you have a ShellViewModel and a ShellView which is just an empty window, and another View/ViewModel where you want to display in your shell at one point. You no longer need to instantiate your views anywhere and just work your way using POCO ViewModels objects:
public class ShellViewModel : Screen
{
public ChildViewModel Child { get; set; }
public void SomeAction()
{
Child = new ChildViewModel(); //Or inject using factory, IoC, etc.
}
}
public class ShellView : Window
{
}
<Window x:Class="WpfApplication1.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cal="http://www.caliburnproject.org">
<Grid>
<ContentControl cal:View.Model="{Binding Child}" />
</Grid>
</Window>

Add behaviour to TextBlock silverlight 3

I want to add a behaviour to a TextBlock in silverlight 3.
I have a behaviour class in a c# file in a different project than my xaml file within my solution.
public class FooBehavior : Behavior<TextBlock>
{
...
}
How do I attach this behaviour to my TextBlock? Would be nice to do without involving c# code.
Include the following lines in the definition of your UserControl:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:myBehaviors="clr-namespace:MyNamespace.Behaviors;assembly=MyAssembly"
Then on the TextBlock have this code:
<TextBlock .....>
<i:Interaction.Behaviors>
<myBehaviors:FooBehaviour/>
</i:Interaction.Behaviors>
</TextBlock>
ChrisF has the correct answer for how to write the Xaml to add the behavior. However, if you have Blend it is even simpler.
Open your project in Blend
On the tools toolbar click the >> button
Click on Behaviors
Find your Behavior and Drag it over your TextBlock and drop it
Blend will add all the proper namespaces for you.

Categories

Resources