|
Thank you for the response.
I think the magic number is a fudge factor to allow your workaround to have a little room to see the mouse before the column actually gets to the MinWidth size. If it finally reaches that size, the column will stop shrinking, but the Grid starts to grow causing dWidth to get larger along with ptGrid.X .
Using binding I ran a test with GridSplitterEx to watch the size of the right column as the splitter moved right. The column would shrink to a size of about 210 pixels (close to MinWidth + 12 ) plus or minus a pixel or two (it wasn't always the same), when the splitter would stop moving.
So your code does workaround the problem for the simplified Window I presented, giving the approximate minimum size for the column, but it did not work unmodified, if I added another column between the splitter and the last column in my XAML.
The problem is not that the MinWidth is ignored, but that the right hand columns are being pushed to the right. Even if several columns are given fixed widths on the right of the splitter, as long as there is one column with a Width of "*" left of the splitter, it will push the right hand columns completely off the window.
Perhaps there is a setting to keep the Grid from growing beyond the edge of its container. If so, that might prevent this behavior.
|
|
|
|
|
Gil Yoder wrote: Using binding I ran a test with GridSplitterEx to watch the size of
the right column as the splitter moved right. The column would shrink to a size
of about 210 pixels (close to MinWidth + 12 ) plus or minus a pixel
or two (it wasn't always the same), when the splitter would stop moving.
Oh yeah, I now have some vague recollection about the grid "randomly" growing if I went past a certain point (the + 12). I don't remember the exact details, but that sounds like the right neighborhood.
Gil Yoder wrote: your code does workaround the problem for the simplified Window I
presented, giving the approximate minimum size for the column, but it did not
work unmodified, if I added another column between the splitter and the last
column in my XAML.
Correct. I only needed a left & right column, so GridSplitterEx only handles that case . Doing it generically for multiple columns on the right seemed like a lot of unnecessary work at the time .
It *is* a bug in .NET & GridSplitter though.
Unfortunately, it is not easy to fix. If you look at the source code for GridSplitter, everything you need access to (to do this right) is private. No virtual methods, etc. to override.
I think if you want to do a generic multi-column fix, you need to do the work in a GridEx : Grid type class and override MeasureOverride & ArrangeOverride and fix the bug there.
Basically copy the source for those two functions and debug to see where the bug is... but really, what is the expected behavior?
Lets say you have something like:
1 (min 200) | 2 (min 200) | 3 (min 200)
No matter how you fix it, it is always going to be possible to run 2 & 3 off the screen. For example... maximize the window, move splitter 1 all the way to the right. Then minimize. 2 and 3 will be gone.
There are a whole bunch of cases you need to handle .
Even my fix will not handle that case for just one splitter. Resizing the window horizontally will not resize the panes.
|
|
|
|
|
SledgeHammer01 wrote: Unfortunately, it is not easy to fix. If you look at the source code for GridSplitter, everything you need access to (to do this right) is private. No virtual methods, etc. to override.
I saw that. After my last note I looked at the code for GridSplitter trying to see what your override was changing, and thought I might look for another virtual method that might do the trick, but it sounds like you've done that already, so I'll save myself some time and look for another windmill to fight.
Thanks again!
|
|
|
|
|
I discovered a pretty easy way to keep from pushing the right hand columns beyond the visible window, and the technique should work for any number of columns. In a two column Grid instead of setting a minimum width on the right hand column, set a maximum width on the left column. If the Grid size is fixed, that is all that would be necessary. The width to set is the desired MinWidth subtracted from width of the Grid . When the left hand column is equal to the maximum size, the splitter won't move any further right.
If the Grid size needs to be elastic, a little coding should handle that so that the MaxWidth of the left column is always equal to Grid.Width minus the desire maximum width of the right hand column.
|
|
|
|
|
I don't think thats going to work. Say I have:
1 | 2 | 3
I set 1 to max 100, 2 to max 100 and 3 to max 100 under the assumption that my grid is 300 wide. At this point there is no way to push 2 and 3 out of the view. But if I maximize my window to 600 pixel wide, now the view will be all messed up since 1, 2 and 3 will only be 100 wide each and you'll have 300 of empty space. Like wise, if I shrunk the window to 250 px, I could push 3 halfway out of view by maximizing 1 and 2.
The "correct" approach as you will see in real production apps like Visual Studio, etc. is that the min and max are limited to proportional amounts of the width (i.e. 25%) and when the frame is resized, they resize all the panes proportionally.
If the grid is 300 wide and 1,2,3 are 100 each, if you resize to 250, you should probably take 16.6 px from each pane. If you resize to 350, you should probably add 16.6 px to each pane.
You should NEVER allow a pane to run off the screen no matter what happens.
|
|
|
|
|
Some time ago I asked here the question how to code adding/removing columns to a Listview at runtime and 'binding columns to viewmodels'
SeldgeHammer came with this solution:
1) The WPF ListView doesn't support data binding on the GridViewColumnCollection out of the box. You can add support for this, not too difficult, but a little bit of work.
2) Once you have a WPF ListView that can support data binding on the GridViewColumnCollection, its just a matter of having your VM return a collection of columns.
3) Some gotcha's you'll run into:
a) a GridViewColumn can only be owned by one GridViewColumnCollection at a time, so you can't return a GridViewColumnCollection from your VM, you need to return an ObservableCollection<gridviewcolumn>.
b) defining a GridViewColumn in code with bindings is a major PITA, so you should devise a way to load them out of a XAML file where you'll again run into "issue a" where you can't share GridViewColumn's.
All these issues are overcomeable... basically what I ended up with was a GridViewEx class that supported two-way binding on the column collection. Remember, you are going to need to save column widths and column order .
I wanted to share a blog on this topic that I ran into the other day. I quite like the solution provided there. Sharing info never hurts right?
http://blogs.msdn.com/b/nathannesbit/archive/2009/03/13/developing-reusable-controls-with-the-model-view-viewmodel-pattern.aspx[^]
|
|
|
|
|
Thanks but you could always consider posting this blog under the original question rather than here.
This isn't a question.
|
|
|
|
|
I doubt he is the author of the blog, so sharing in this manner is excellent, he got my 5
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
I am facing problems with binding itemscontrol to a list of values. Below is my code in details:
Model code:
public class Employee
{
public string Name { get; set; }
public string Salary { get; set; }
}
public class Department
{
public string DepartmentName { get; set; }
public List<Employee> EmployeeDetails { get; set; }
}
View Model Code:
public ObservableCollection<Department> Departments { get; set; }
Departments = new ObservableCollection<Department>();
Departments.Add(new Department {DepartmentName = "TECH", EmployeeDetails = new List<Employee> {new Employee {Name = "XYZ", Salary = "10000.00" }}});
XAML:
<ItemsControl ItemsSource="{Binding Departments}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Path=DepartmentName}" Margin="12,12,12,0" VerticalAlignment="Top">
<Border BorderBrush="Black" BorderThickness="1" x:Name="border1">
<Grid Height="50">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding EmployeeDetails.Name}" TextWrapping="Wrap" FontSize="10"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding EmployeeDetails.Salary}" TextWrapping="Wrap" FontSize="10"/>
</Grid>
</Border>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The data is not displaying with the code.
If the Department class is as below
public class Department
{
public string DepartmentName { get; set; }
public Employee EmployeeDetails { get; set; }
}
Then it works fine. But I need Department class should be as
public class Department
{
public string DepartmentName { get; set; }
public List<Employee> EmployeeDetails { get; set; }
}
And with this the data is not displaying. Please help me out.
Thanks in Advance,
|
|
|
|
|
You are going to have to put EmployeeDetails in another items container, as the way you have it now, it is not binding to the collection. So, instead of
<Grid Height="50">
<Grid.RowDefinitions>
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center"
VerticalAlignment="Center" Text="{Binding EmployeeDetails.Name}"
TextWrapping="Wrap" FontSize="10"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Text="{Binding EmployeeDetails.Salary}"
TextWrapping="Wrap" FontSize="10"/>
</Grid>
you should have something like this
<ItemsControl ItemsSource="{Binding Path=EmployeeDetails}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" HorizontalAlignment="Center"
VerticalAlignment="Center" Text="{Binding Name}"
TextWrapping="Wrap" FontSize="10" Margin="5"/>
<TextBlock Grid.Column="1" HorizontalAlignment="Center"
VerticalAlignment="Center" Text="{Binding Salary}"
TextWrapping="Wrap" FontSize="10" Margin="5" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
modified 31-Jan-12 6:23am.
|
|
|
|
|
Thanks Eric Allman.
It works now.
|
|
|
|
|
Glad to help. My Name is Wayne Gaylard - Eric Allman is an author I quote in my signature.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
|
|
|
|
|
|
Thanks
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
|
|
|
|
|
hi everyone,
Can anybody give me a solution for focusing on an element in a view from ViewModel by binding?????
|
|
|
|
|
You might want to look at the solution provided by Anvaka here[^].
|
|
|
|
|
It is a good post. The only thing for the OP to be aware of though is that focus in WPF is a tricksy thing. Sometimes what you think you are focusing on isn't what ends up focused.
|
|
|
|
|
Good link!
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
|
|
|
|
|
I thought of writing one myself for the OP, then found this sample. There wasn't a lot I could have done to improve on it, so I thought I'd leave it alone.
|
|
|
|
|
My current project has problems in the login dialogue, focusing on the first text box when it opens - I shall be busy tomorrow morning implementing this to see if it works - again good find - and timing was excellent.
When I was a coder, we worked on algorithms. Today, we memorize APIs for countless libraries — those libraries have the algorithms - Eric Allman
|
|
|
|
|
Hmm... was kind of envisioning something along the lines of a bindable version of FocusManager.FocusedElement / ElementName binding, but that would mean the VM would be tightly coupled to view control names . Not too big on having to put an attached property on x controls that I might want to set focus to (and having x public bool properties to boot). Not too sure the VM should be the one deciding focus anyways. Seems like a job for the view. I'm thinking 99% of cases can be handled in XAML with triggers .
|
|
|
|
|
Do you mean "event" as in raising a real event? If so, the VM raising events to the V is kinda backwards and not really much different then just exposing public properties in the VM that the V binds to.
On the drive in to work, I thought about this more... I'm now thinking something along the lines of following the .NET control model. I think using the built in VisualStateManager could possibly work. I haven't tried it, so it may be dependent on something , if so, something very similiar to it. This way, you can handle a bunch of different states (in the XAML) with a single object.
Kinda all the same... 50 public bools vs. 50 events vs. a visual state manager. I'd definitely go with some design that can do multiple things off of one property / event / whatever.
|
|
|
|
|
Wait, I kind of read your response as "I'm going to raise Event1" to signal that something should happen in the view. How are you going to tell the view through Event1 to set focus to 1 of 50 controls? Aren't you going to need one event for every state? What I mean is, are you defining a custom eventargs that contains which control to set focus to? The OP poster wanted to set focus from the VM to any one of those 50 controls.
Where I was headed with the VSM is that they already have a method for "switching" in the XAML based on the state. No code behind.
I think we are both trying to say the same thing in different ways LOL, that you should be able to do different things through a single property, DP, whatever.
|
|
|
|
|
Gotcha.
OP sounded like he wanted to randomly set focus to random controls at random times. Otherwise, why would you need a bindable solution?
'50' as in the sense of multiple controls. If I have a dialog with 3 edit boxes, I thought OP wanted to be able to set focus to any of the 3 edit boxes.
If you wanted to do that, you'd either need a custom eventargs to pass a param, or some other object like VSM.
If you are trying to accomplish something like "hey! you were a douche and you put 24 in an edit box that only allows 50 -> 100, so I'm going to focus the edit box for you!" then I wouldn't use any of these solutions and would do it with validation templates.
|
|
|
|
|
this solution is for frameworkelements but i want to focus on a gridviewcolumn....
is there any solution?????
|
|
|
|