|
I am using WPF, C#, Linq to Sql -- I have a stored procedure and I am trying to bind the results to a treeview two levels deep. Below is some of the code I thought might help understand better, I am not sure if I needed to post this much code, but I can remove the uneeded code. I am having trouble figuring out the bindings with the data-templates. Any suggestions or comments would be appreciated.
Here is part of the view model I am using
public sealed class AViewModel : ViewModel
{
public sealed class ItemsToGet
{
public Guid? Id {get; set; }
public int? TNumber { get; set;}
public string Title { get; set; }
public string Description { get; set; }
public string FullName { get; set;}
}
private Guid mText = Guid.Empty;
private ObservableCollection<ItemsToGet> mHistory = new ObservableCollection<ItemsToGet>();
public ObservableCollection<ItemsToGet> History
{
get
{
return mHistory;
}
}
public Guid SearchText
{
get
{
return mText ;
}
set
{
mText = value;
OnPropertyChanged("SearchText");
}
}
var itemlist = from s in context.GetHistory(mText)
select new ItemsToGet()
{
Id = s.Id,
TNumber = s.TNumber,
Title = s.Title,
Description = s.Description,
FullName = s.FullName
};
List<ItemsToGet> Results = itemlist.ToList();
mHistory.Clear();
Results.ForEach(b => mHistory.Add(b));
Here is the View Code Behind
public partial class AView : UserControl
{
public AView()
{
InitializeComponent();
AViewModel vm = this.DataContext as AViewModel;
}
}
Xaml -- I want to top level to display the Title, and the child(second level to be the TNumber)
<TreeView ItemsSource="{Binding History}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding History}">
<TextBlock Foreground="Red" Text="{Binding Title}" />
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding History}">
<TextBlock Text="{Binding TNumber}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>
Here is a snapshot of what the results look like, there are more rows than this, but this is the format.
Trying to display it like below. Thanks for any comments or suggestions.
Design 1
--Tnumber 1
--TNumber 2
Design 2
--TNumber 1
--TNumber 2
--TNumber 3
Design 3
--TNumber 1
ETC
ETC
|
|
|
|
|
|
You need 2 clases a Design class and a Tnumber class, your Design class must have an observable collection of Tnumbers.
Populate the Design class with the unique of the design field. In the tnumber collection add the records for each design type.
Binid your treeview to the design collection, bind the hierarchy template to the tnumber collection.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Trying to use VisualTreeHelper.HitTest on a TreeView. I have two arbitrary items. TreeViewItem1 and TreeViewItem2. These items may appear anywhere on the tree and have any sort of relationship (different parents, etc.). I've gotten the top left point of the two items. pt1 and pt2. I want to find the visible TreeViewItems in between. So I did:
VisualTreeHelper.HitTest(ParentTreeView, new HitTestFilterCallback(A), new HitTestResultCallback(B), new GeometryHitTestParameters(new RectangleGeometry(new Rect(0, pt1.Y, ParentTreeView.ActualWidth, (pt2.Y + 1) - pt1.Y))));
HitTestFilterBehavior A(DependencyObject potentialHitTestTarget)
{
if (potentialHitTestTarget is TreeViewItemEx)
{
if (((UIElement)potentialHitTestTarget).IsVisible)
System.Diagnostics.Debug.WriteLine(potentialHitTestTarget);
}
return HitTestFilterBehavior.Continue;
}
HitTestResultBehavior B(HitTestResult result)
{
return HitTestResultBehavior.Continue;
}
This code is working for the most part, except it's also returning parent items that it shouldn't. If my tree looks like:
1
_2
__3
and the two items in question are 2 & 3, the hit-test also returns 1.
A more ugly example is:
Root
_NodeWithChildren1
_NodeWithChildren2
_NodeWithChildren3
__1
__2
__3
the tree looks exactly like that on the screen. The items in question are _NodeWithChildren3 and __1. The hit-test returns Root and _NodeWithChildren1 and _NodeWithChildren2 as well.
Any ideas? I have confirmed that I am getting the correct item1 & item2 that I think I am getting and I have confirmed that the points I am getting are correct as well.
|
|
|
|
|
Cant you cast the object or check the object using TypeOf, and then check were it is in the treèviewcontrol?
|
|
|
|
|
I posted on this a while back, and I'v tried some things but still cannot get this to work.
The Problem
When I have multiple tabs open, and I click the Close X on a NON-ACTIVE tab, the active tab is closed.
The XAML
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="..\Resources.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type TabItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate >
<Grid HorizontalAlignment="Stretch" Height="22">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2" ></RowDefinition>
<RowDefinition Height="Auto" ></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="1"
Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem} }, Path=Header}"
VerticalAlignment="Bottom" Margin="4,0,8,0"/>
<Button Grid.Row="1"
Grid.Column="1"
Height="16"
Width="16"
BorderBrush="{x:Null}"
Background="{x:Null}"
Foreground="#FF224A71"
VerticalAlignment="Center"
Padding="3,0"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=DataContext.CloseTabCommand}">
<TextBlock Text="x"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="0,0,0,2"/>
<Button.ToolTip>
<controls:ToolTipEx Style="{StaticResource TooltipStyle}"
HeaderText="Close"
Icon="/FMG.UI.WPF;component/Media/Images/closetab_24.png"
ContentAreaText="Closes this tab"/>
</Button.ToolTip>
<Button.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#4BFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Button.OpacityMask>
</Button>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
The problem as I see it is that the view model doesn't know which tab fired the command.
Can someone help me figure this out?
Thanks
If it's not broken, fix it until it is
|
|
|
|
|
I too was running into this same problem with this EXACT command. However this article on c# corner and this article on CP helped me to fix it.
Hope it works!
|
|
|
|
|
I am using this in the code behind for a xaml page and it works fine for retrieving the data for a listbox:
_______________________________________________________________
SLConnDomainContext dbContext = new SLConnDomainContext();
private LoadOperation<Employee> loadOp;
ObservableCollection<Employee> data = new ObservableCollection<Employee>();
public Filters()
{
InitializeComponent();
loadOp = this.dbContext.Load(this.dbContext.GetEmployeesQuery());
loadOp.Completed += new EventHandler(loadOp_Completed);
}
void loadOp_Completed(object sender, EventArgs e)
{
foreach (Employee emp in loadOp.Entities)
{
data.Add(emp);
}
dataForm.ItemsSource = data;
}
I would like to move to a MVVM approach and have created a viewmodel to retrieve the data and pass it into a view by creating an instance of my viewmodel and setting the datacontext property of my listbox. The viewmodel works fine when I am just creating some mock data and populating a list. However, due to the asynchronous nature of using a loadoperation with silverlight, the above code doesn't work with the MVVM approach for me. The data is retrieved but it appears that it is after my view has already loaded so it never appears. Below is my code:
Viewmodel:
______________________________________________________________
{
public partial class EmployeeService
{
private SLConnDomainContext Context = new SLConnDomainContext();
private LoadOperation<Employee> loadOp;
public ObservableCollection<Employee> employees = new ObservableCollection<Employee>();
public EmployeeService()
{
loadOp = Context.Load(Context.GetEmployeesQuery(), LoadBehavior.MergeIntoCurrent, employeeCallBack, null);
}
void employeeCallBack(LoadOperation<Employee> op)
{
foreach (Employee emp in loadOp.Entities)
{
employees.Add(emp);
}
_myEmployees = employees;
MessageBox.Show("I have " + employees.Count + " employees");
}
public IEnumerable<Employee> GetEmployees()
{
return employees;
}
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Employee> _myEmployees;
public ObservableCollection<Employee> myEmployees
{
get { return _myEmployees; }
set
{
myEmployees = value;
OnPropertyChanged("myEmployees");
}
}
private int _EmployeeID;
public int EmployeeID
{
get { return _EmployeeID; }
set
{
_EmployeeID = value;
OnPropertyChanged("EmployeeID");
}
}
private int _VacationHours;
public int VacationHours
{
get { return _VacationHours; }
set
{
_VacationHours = value;
OnPropertyChanged("VacationHours");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
This is set in the constructor for the view's code behind:
______________________________________________________________
public LayoutTest()
{
InitializeComponent();
EmployeeService myservice = new EmployeeService();
EmployeeList.DataContext = myservice;
}
I have the databinding set correclty as it works if I use something like this in place of the above GetEmployees():
______________________________________________________________
public IEnumerable<Employee> GetEmployees()
{
List<Employee> employees = new List<Employee>();
EmployeeService test = new EmployeeService();
foreach (Employee emp in test.GetEmployees())
{
employees.Add(emp);
}
Employee employee = new Employee();
employee.EmployeeID = 1111;
employee.VacationHours = 100;
employees.Add(employee);
employee = new Employee();
employee.EmployeeID = 1112;
employee.VacationHours = 62;
employees.Add(employee);
employee = new Employee();
employee.EmployeeID = 1113;
employee.VacationHours = 132;
employees.Add(employee);
return employees;
}
I am sure this is due to the asynchronous call but I don't know how to fix it. Thanks for any help.
|
|
|
|
|
Why do you have _employees and _myEmployees? The main issue is that _myEmployees = employees doesn't trigger a change notification, so you'd have to call OnPropertyChanged("myEmployees") after the assignment. That is the correct method, but then employees should be a local object, not a class member.
|
|
|
|
|
Wow! Thank you....That was it.
|
|
|
|
|
I could not find no example on how to write a wpf control that wraps c++ win32 window. If some one could provide me with a link to a newbie-like tutorial/documentation (sample code would be good too) on how to create c# libraries that wrap c++ code I would be very thankful.
Thanks in advance.
|
|
|
|
|
|
Hi!
Thx for the link. I found that one my self and I tried to modify the sample code to my needs but i failed.
I'll try to explain more what I'm trying to do.
So I have 3rd party OpenGL application written in C++ that is capable to show its output on another process window by passing a HWND pointer of that window (re-parenting).
If I create basic C++ Win32 aplication and pass its window HWND to that 3rd application I see output of that application in my application window.
Since I don't know C++ programming that well and I'm a little better at C#, I would like to create a WPF control that wraps C++ window in a dll that I can use in my WPF project.
Now the problem is that I can't figure out how to override WM_PAINT function so that WPF would be able to render that control correctly.
Because now I get that control instantiated and I get the HWND of that control (which is different of the WPF window hosting it) but when I pass it to that 3rd party application nothing happens.
My guess is that WM_PAINT is being called correctly but WPF window is not rendering that control because it knows nothing of WM_PAINT ?!
Now, the MSDN resource is a bit difficult for me to figure out how to solve my problem. Mostly because I need some easy reading on how to write managed c++/clr code.
Any suggestion on some websites or books that explain this subject (on elementary school level ) ?
Thx again!
|
|
|
|
|
You can get the native HWND of a WPF control / window. Wait for the SourceInitialized event and then:
HwndSource hWndSource = (HwndSource)PresentationSource.FromVisual(window);
the HWND is in hWndSource.Handle. WPF hides WM_PAINT from you so it can do all the double buffering, effects, transformations, etc.
|
|
|
|
|
So I have PInvoked BeginPaint() and EndPaint() funcrions also.
And I'm able to draw inside my win32 window from there.
But my 3rd party application still can't and I don't know what else do I need to override to make it work.
At this point there is no difference between win32 window hosted in WPF application and win32 window created by c++ win32 application or is there ?!
Maybe type of class inside CreateWindowEx function ("static") should be something different, or some of window parameters should be changed.
My guess is that WPF is preventing win32 window from communicating with 3rd party process. Response from 3rd party app is: "visual not possible"
Here is link to my project if anyone interested to look what I did so far.
http://sdrv.ms/10VSWbD[^]
Don't know if there is a way to simulate my situation by trying to redirect (reparent) some other application (that uses win32) window output to my app. I'm not in position to share that 3rd party application that I'm using.
|
|
|
|
|
Did you try passing the 3rd party app the HWND from:
HwndSource hWndSource = (HwndSource)PresentationSource.FromVisual(window);
The HWND in hWndSource.Handle and bypassing your C++ app entirely?
I don't think "visual not possible" is a WPF error, sounds like its coming from the 3rd party vendor. Have you tried contacting them if they support redirection?
|
|
|
|
|
Yes I tried your suggestion and still no success.
The 3rd party vendor don't consider this to be a valid customer API request as this is something they use internally (they have couple of apps that can do this and they have some interop wpf dll's for this but it is not exposed for others)
|
|
|
|
|
Hmmm... maybe its not possible then. If you can do it in C++, then you should be able to take that C++ window and host it on a WPF form. My only other suggestion would be to maybe package it as an ActiveX control and then host that on the WPF form natively. Not sure if it will work though...
|
|
|
|
|
Just as a note, this two methods return the same hwnd (I was using the later option).
Window www = App.Current.MainWindow;
HwndSource hwndS = (HwndSource)PresentationSource.FromVisual(www);
Console.WriteLine("hwndSource: " + hwndS.Handle);
IntPtr hwnd = new WindowInteropHelper(www).Handle;
Console.WriteLine("hwnd: " + hwnd);
I also thought it would be simple. Just create a c++ win32 window inside of wpf and all would work but somehow it is not that simple. I'll try some more options I found online.
My guess is that I need to somehow paste info from BeginPaint(IntPtr hwnd, PAINTSTRUCT ps) PAINTSTRUCT to overriden OnRender(DrawingContext dc) DrawingContext.
But that probably won't work either.
Anyway thx for help.
|
|
|
|
|
I just noticed it now in your previous response, but you said they have interop WPF dlls that are working? Why don't you just use those? Are those written in C# or C++? If they are written in C#, you can view the exact code by using ILSpy, .NET Reflector, etc. If they are written in C++, you can view the DLL exports easily using the dumpbin utility that comes with Visual Studio.
|
|
|
|
|
I believe they are written in C#, or maybe they are managed C++.
But they name says that they are _.Interop.Wpf.dll
Will try to examine it as you suggested.
|
|
|
|
|
Hi,
You're rather trying to do something that will break WPF!
WPF is rendered using DirectX. The whole thing, there is just a window wrapper for win32 environment. You cannot do anything by passing it an WM_PAINT message.
Here comes the fix. Set up a winforms host inside your app xaml. Put a label control (winforms equivalent of STATIC) inside the host . Set the text to empty. get it's HWND by getting its Handle property and pass it to your native library that does OpenGL stuff through P/Invoke.
Here is a MSDN Walkthrough to guide you. Just replace that MaskedTextBox code with a Label.
Good Luck!
|
|
|
|
|
How to create radio buttons dynamically as shown below in WPF
Group1 Group2 . . . . . GroupN
A 1
B 2
C 3 . . . . . N
|
|
|
|
|
Id proberbly use a DataTable or a ListView for this, but there are also other more cumbersome possibilities:
WPF-Drawing Canvas Control[^]
|
|
|
|
|
Host your groups and radio buttons in a collection control, datagrid, listview, treeview, itemscontainer and bind the itemssource to your underlying collection.
Limit n to a workable number.
Never underestimate the power of human stupidity
RAH
|
|
|
|