Best wpf questions in September 2011

I'm a .Net, C# and WPF programmer. Is Expression Blend worth?

14 votes

I mean, as a normal developer, is there something that I will achieve with Expression Blend that I won't using VS? I have no idea of Expression Blend and at first sight didn't look very friendly / easy to learn.

What do you thing out there? It's worth the time learning to use it or I will do the same as I do with VS?

Thanks!

EDIT: I know what Microsoft says about the tools. What I want to know is if you, as a developer like me, tried Expression Blend and found that it was a waste of time or you thought it was a good tool and you stopped developing the WPF GUIs from VS and switched to EB.

I have it and rarely use it.

I greatly dislike all the extra markup that gets added to the XAML files, and prefer to know what I'm doing to just dragging/dropping items.

The few times I have used it have been to pull out the default styles or templates of a control, or to build something like a gradient, animation, or path, and then copy/paste the XAML into my project.

It's nice if you're into drag/drop coding, or if you're working on a large enough team to be have a separate UI and Coding team, but other than that I don't use it for solo development since I have to maintain the XAML mess it generates.

Damping Effect of Spring-Mass System (or is this ElasticEase?)

10 votes

I'm trying to emulate an animation effect in code (almost any language would do as it appears to be math rather than language). Essentially, it is the emulation of a mass-spring system. I've been looking at WPF/Silverlight's ElasticEase and this appears to be pretty close to what I'm looking for, but not quite.

First of all, here's what I'm looking for - an object, travelling a certain number of seconds, hitting a location and immediately slowing down to ocsillate for a certain number of seconds to rest at the same point where damping was applied. So to visualize this, let's say I have a 600w/900h canvas and I have an square that begins to animate from 900px to 150px in a TranslateTransform.Y. It takes 4 seconds to reach 150px height (187.5px per second), at which stage it immediated gets damped and only travels about 35px more for 0.4 seconds (87.5px per second) to 115px height, then rebounds down for 1 second to 163px height (48px and 48px per second) and then rebounds back up to 146px (17px and 17px per second) and so on until the ocillations slow it to its final resting place of 150px. The ocillation period is 16 seconds.

The example I described above is the top left blue rectangle here: enter image description here

Here's what I will know in advance - the pixel distance and number of seconds it takes to get from point A to point B, the number of seconds for ocillation. Things like mass don't seem to matter.

I've tried ElasticEase and the issue seems to be that I can't get the object to travel with no easing for 4 seconds and then "bounce" for the next 16 seconds. The .Springiness is also always way too much, even if I set it to be a really high number like 20.

ILSpy show's its function as:

protected override double EaseInCore(double normalizedTime)
        {
            double num = Math.Max(0.0, (double)this.Oscillations);
            double num2 = Math.Max(0.0, this.Springiness);
            double num3;
            if (DoubleUtil.IsZero(num2))
            {
                num3 = normalizedTime;
            }
            else
            {
                num3 = (Math.Exp(num2 * normalizedTime) - 1.0) / (Math.Exp(num2) - 1.0);
            }
            return num3 * Math.Sin((6.2831853071795862 * num + 1.5707963267948966) * normalizedTime);
        }

I've included 2 videos and and an Excel file in a zipped folder on DropBox. I guess this question will be more of a work-in-progress as folks ask more clarifying questions.

(DISCLAIMER: I don't know what I'm talking about when it comes to much of this stuff)

Skip the physics and just go straight to the equation.

parameters: “Here's what I will know in advance - the pixel distance [D] and number of seconds [T0] it takes to get from point A to point B, the number of seconds for oscillation [T1].” Also, I'll add as free parameters: the maximum size of oscillation, Amax, the damping time constant, Tc, and a frame rate, Rf, that is, at what times does one want a new position value. I assume you don't want to calculate this forever, so I'll just do 10 seconds, Ttotal, but there are a variety of reasonable stop conditions...

code: Here's the code (in Python). The main thing is the equation, found in def Y(t):

from numpy import pi, arange, sin, exp

Ystart, D = 900., 900.-150.  # all time units in seconds, distance in pixels, Rf in frames/second
T0, T1, Tc, Amax, Rf, Ttotal = 5., 2., 2., 90., 30., 10. 

A0 = Amax*(D/T0)*(4./(900-150))  # basically a momentum... scales the size of the oscillation with the speed 

def Y(t):
    if t<T0:  # linear part
        y = Ystart-(D/T0)*t
    else:  # decaying oscillations
        y = Ystart-D-A0*sin((2*pi/T1)*(t-T0))*exp(-abs(T0-t)/Tc)
    return y

y_result = []
for t in arange(0, Ttotal, 1./Rf):  # or one could do "for i in range(int(Ttotal*Rf))" to stick with ints    
    y = Y(t)
    y_result.append(y)

The idea is linear motion up to the point, followed by a decaying oscillation. The oscillation is provided by the sin and the decay by multiplying it by the exp. Of course, change the parameters to get any distance, oscillation size, etc, that you want.

enter image description here

notes:

  1. Most people in the comments are suggesting physics approaches. I didn't use these because if one specifies a certain motion, it is a bit over-doing-it to start with the physics, go to the differential equations, and then calculate the motion, and tweak the parameters to get the final thing. Might as well just go right to the final thing. Unless, that is, one has an intuition for the physics that they want to work from.
  2. Often in problems like this one wants to keep a continuous speed (first derivative), but you say “immediately slows down”, so I didn't do that here.
  3. Note that the period and amplitude of the oscillation won't be exactly as specified when the damping is applied, but that's probably more detailed than you care about.
  4. If you need to express this as a single equation, you can do so using a “Heaviside function”, to turn the contributions on and off.

At the risk of making this too long, I realized I could make a gif in GIMP, so this is what it looks like:

enter image description here

I can post the full code to make the plots if there's interest, but basically I'm just calling Y with different D and T0 values for each timestep. If I were to do this again, I could increase the damping (i.e., decrease Tc), but it's a bit of a hassle so I'm leaving it as is.

Expanders in Grid

8 votes

This is going to be straight forward no doubt, but for what ever reason, my mind is drawing a blank on it.

I've got a small, non-resizeable window (325x450) which has 3 Expanders in it, stacked vertically. Each Expander contains an ItemsControl that can potentially have a lot of items in and therefore need to scroll.

What I can't seem to get right is how to layout the Expanders so that they expand to fill any space that is available without pushing other elements off the screen. I can sort of achieve what I'm after by using a Grid and putting each expander in a row with a * height, but this means they are always taking up 1/3 of the window each which defeats the point of the Expander :)

Crappy diagram of what I'm trying to achieve:

enter image description here

If you don't mind a little code-behind, you could probably hook into the Expanded/Collapsed events, find the parent Grid, get the RowDefinition for the expander, and set the value equal to * if its expanded, or Auto if not.

For example,

Expander ex = sender as Expander;
Grid parent = FindAncestor<Grid>(ex);
int rowIndex = Grid.GetRow(ex);

if (parent.RowDefinitions.Count > rowIndex && rowIndex >= 0)
    parent.RowDefinitions[rowIndex].Height = 
        (ex.IsExpanded ? new GridLength(1, GridUnitType.Star) : GridLength.Auto);

And the FindAncestor method is defined as this:

public static T FindAncestor<T>(DependencyObject current)
where T : DependencyObject
{
    // Need this call to avoid returning current object if it is the 
    // same type as parent we are looking for
    current = VisualTreeHelper.GetParent(current);

    while (current != null)
    {
        if (current is T)
        {
            return (T)current;
        }
        current = VisualTreeHelper.GetParent(current);
    };
    return null;
}

Trying to understand of DependencyProperty

8 votes

Being new to WPF, and its apparently amazing ability to change, bind, enable, and otherwise manipulate. I'm trying to get a mental overview of what is happening and hope some can either confirm or correct my readings.

Before WPF, you have delegates and events. You could have a dozen controls all listening (via being registered to the event), so when the event fires, all other controls will be notified automatically and can act on however they were so coded. Such as...

From Code Behind, you would do something like

GotFocus += MyMethodToDoSomething;

Then, the signature method

private void MyMethodToDoSomething(object sender, RoutedEventArgs e)
{
  .. do whatever
}

Additionally, by using standard getter / setter, the setter can call its own methods in its own class to do something every time someone tries to get or set a value

private int someValue;
public int SomeValue
{
   get { this.DoSomeOtherThing();
         return someValue;
       }

   set { this.DoAnotherThing();
        someValue = value;
}

Now, there's dependency properties, and the one/two-way binding. I understand (I think) about one-way to simulate more of a read-only operation.

Anyhow, with two way binding, the dependencies automatically notify anyone "depending" on a change in either the source or target respectively, without an explicit check if something has subscribed to an event, the framework automatically handles the announcing of the change to the respective controls (target or source).

So, let me through this scenario out with an old Add/Edit Save/Cancel maintenance form. In an older framework, if someone clicked on an add or edit button, all the data entry fields would become "enabled" with either blank data for a new record, or editing existing data. At the same time, the add/edit buttons would become disabled, but the Save/Cancel buttons would now become enabled.

Likewise when finished via Save/Cancel, it would disable all the entry fields, save/cancel, and re-enable the Add/Edit buttons.

I don't quite understand how such this type of scenario would be handled under this dependency property scenario (yet), but am I close? I also understand you can bind to almost anything, including color schemes, show/hide, fonts, etc... But I'm taking small steps on trying to really grasp this stuff.

Thanks.

The poster has requested that I repost my comment as an answer. Happy to oblige :-)

Also I've found this book very helpful: http://www.amazon.com/WPF-4-Unleashed-Adam-Nathan/dp/0672331195

My own experience with WPF involves going back between a bunch of different resources as I try to get my program to work. There's so much stuff in WPF it's really hard to keep it all in your head as you are learning it.

GC is forced when working with small images (<=4k pixel data)?

7 votes

I'm seeing the performance counter "# Induced GC" (which should stay at zero in a perfect app) increasing rapidly when processing small files (<= 32x32) via WriteableBitmap.

While this isn't a significant bottleneck inside a small app, it becomes a very huge problem (app freezing at 99.75% "% Time in GC" for several seconds at each step) when there exist some thousand objects in memory (ex: EntityFramework context loaded with many entities and relationships).

Synthetic test:

var objectCountPressure = (
    from x in Enumerable.Range(65, 26)
    let root = new DirectoryInfo((char)x + ":\\")
    let subs = 
        from y in Enumerable.Range(0, 100 * IntPtr.Size)
        let sub =new {DI = new DirectoryInfo(Path.Combine(root.FullName, "sub" + y)), Parent = root}
        let files = from z in Enumerable.Range(0, 400) select new {FI = new FileInfo(Path.Combine(sub.DI.FullName, "file" + z)), Parent = sub}
        select new {sub, files = files.ToList()}
    select new {root, subs = subs.ToList()}
    ).ToList();

const int Size = 32;
Action<int> handler = threadnr => {
    Console.WriteLine(threadnr + " => " + Thread.CurrentThread.ManagedThreadId);
    for (int i = 0; i < 10000; i++)    {
        var wb = new WriteableBitmap(Size, Size, 96, 96, PixelFormats.Bgra32, null);
        wb.Lock();
        var stride = wb.BackBufferStride;
        var blocks = stride / sizeof(int);
        unsafe {
            var row = (byte*)wb.BackBuffer;
            for (int y = 0; y < wb.PixelHeight; y++, row += stride)
            {
                var start = (int*)row;
                for (int x = 0; x < blocks; x++, start++)
                    *start = i;
            }
        }
        wb.Unlock();
        wb.Freeze();     }
};
var sw = Stopwatch.StartNew();
Console.WriteLine("start: {0:n3} ms", sw.Elapsed.TotalMilliseconds);
Parallel.For(0, Environment.ProcessorCount, new ParallelOptions{MaxDegreeOfParallelism = Environment.ProcessorCount}, handler);
Console.WriteLine("stop : {0:n2} s", sw.Elapsed.TotalSeconds);

GC.KeepAlive(objectCountPressure);

I can run this test using "const int Size = 48" a dozen times: It always returns in ~1.5s and "# Induced GC" sometimes increases by 1 or 2.

When I change "const int Size = 48" into "const int Size = 32" then something very very bad is happening: "# Induced GC" increases by 10 per second and the overall runtime now is more than a minute: ~80s ! [Tested on Win7x64 Core-i7-2600 with 8GB RAM // .NET 4.0.30319.237 ]

WTF!?

Either the Framework has a very bad bug or I'm doing something entirely wrong.

BTW:
I came around this problem not by doing image processing but by just using a Tooltip containing an Image against some database entities via a DataTemplate: This worked fine (fast) while there didn't exist very much objects in RAM -- but when there existed some million other objects (totally unrelated) then showing the Tooltip always delayed for several seconds, while everything else just was working fine.

TL;DR: Probably the best solution would be to create a small pool of WriteableBitmaps and reuse them rather than creating them and throwing them away.

So I started spelunking around with WinDbg to see what was causing the collections to happen.

First I added a call to Debugger.Break() to the start of Main to make things easier. I also added my own call to GC.Collect() as a sanity check to make sure my breakpoint worked ok. Then in WinDbg:

0:000> .loadby sos clr
0:000> !bpmd mscorlib.dll System.GC.Collect
Found 3 methods in module 000007feee811000...
MethodDesc = 000007feee896cb0
Setting breakpoint: bp 000007FEEF20E0C0 [System.GC.Collect(Int32)]
MethodDesc = 000007feee896cc0
Setting breakpoint: bp 000007FEEF20DDD0 [System.GC.Collect()]
MethodDesc = 000007feee896cd0
Setting breakpoint: bp 000007FEEEB74A80 [System.GC.Collect(Int32, System.GCCollectionMode)]
Adding pending breakpoints...
0:000> g
Breakpoint 1 hit
mscorlib_ni+0x9fddd0:
000007fe`ef20ddd0 4154            push    r12
0:000> !clrstack
OS Thread Id: 0x49c (0)
Child SP         IP               Call Site
000000000014ed58 000007feef20ddd0 System.GC.Collect()
000000000014ed60 000007ff00140388 ConsoleApplication1.Program.Main(System.String[])

So the breakpoint worked OK, but when I let the program continue it was never hit again. It seemed the GC routine was being called from somewhere deeper. Next I stepped into the GC.Collect() function to see what it was calling. To do this more easily I added a second call to GC.Collect() immediately after the first and stepped into the second one. This avoided stepping through all the JIT compilation:

Breakpoint 1 hit
mscorlib_ni+0x9fddd0:
000007fe`ef20ddd0 4154            push    r12
0:000> p
mscorlib_ni+0x9fddd2:
000007fe`ef20ddd2 4155            push    r13
0:000> p
...
0:000> p
mscorlib_ni+0x9fde00:
000007fe`ef20de00 4c8b1d990b61ff  mov     r11,qword ptr [mscorlib_ni+0xe9a0 (000007fe`ee81e9a0)] ds:000007fe`ee81e9a0={clr!GCInterface::Collect (000007fe`eb976100)}

After a little stepping I noticed a reference to clr!GCInterface::Collect which sounded promising. Unfortunately a breakpoint on it never triggered. Digging further into GC.Collect() I found clr!WKS::GCHeap::GarbageCollect which proved to be the real method. A breakpoint on this revealed the code that was triggering the collection:

0:009> bp clr!WKS::GCHeap::GarbageCollect
0:009> g
Breakpoint 4 hit
clr!WKS::GCHeap::GarbageCollect:
000007fe`eb919490 488bc4          mov     rax,rsp
0:006> !clrstack
OS Thread Id: 0x954 (6)
Child SP         IP               Call Site
0000000000e4e708 000007feeb919490 [NDirectMethodFrameStandalone: 0000000000e4e708] System.GC._AddMemoryPressure(UInt64)
0000000000e4e6d0 000007feeeb9d4f7 System.GC.AddMemoryPressure(Int64)
0000000000e4e7a0 000007fee9259a4e System.Windows.Media.SafeMILHandle.UpdateEstimatedSize(Int64)
0000000000e4e7e0 000007fee9997b97 System.Windows.Media.Imaging.WriteableBitmap..ctor(Int32, Int32, Double, Double, System.Windows.Media.PixelFormat, System.Windows.Media.Imaging.BitmapPalette)
0000000000e4e8e0 000007ff00141f92 ConsoleApplication1.Program.<Main>b__c(Int32)

So WriteableBitmap's constructor indirectly calls GC.AddMemoryPressure, which eventually results in collections (incidentally, GC.AddMemoryPressure is an easier way to simulate memory usage). This doesn't explain the sudden change in behaviour when going from a size of 33 to 32 though.

ILSpy helps out here. In particular, if you look at the constructor for SafeMILHandleMemoryPressure (invoked by SafeMILHandle.UpdateEstimatedSize) you'll see that it only uses GC.AddMemoryPressure if the pressure to add is <= 8192. Otherwise it uses its own custom system for tracking memory pressure and triggering collections. A bitmap size of 32x32 with 32-bit pixels falls under this limit because WriteableBitmap estimates the memory use as 32 * 32 * 4 * 2 (I'm not sure why the extra factor of 2 is there).

In summary, it looks like the behaviour you're seeing is the result of a heuristic in the framework that doesn't work so well for your case. You might be able to work around it by creating a bitmap with bigger dimensions or a bigger pixel format than you need so that the estimated memory size of the bitmap is > 8192.

Afterthought: I guess this also suggests that collections triggered as a result of GC.AddMemoryPressure are counted under "# Induced GC"?

Model-View-Presenter: Why is model static?

7 votes

I've been attempting to fully understand the Model View Presenter pattern as it applies to C#. I have one question I can't wrap my head around.

In many examples, I noticed that model is defined as static and is constructed in the Presenter base class (often a generic class).

How does one have multiple model classes in that case? From my understanding, every presenter created will only be able to reference a single model class.

The example I'm looking at now can be found here: http://wesaday.files.wordpress.com/2009/01/finalzip.doc (rename to .zip). It's from this tutorial: http://wesaday.wordpress.com/2009/01/30/winform-model-view-presenter-part-v-the-view/

The guess the overall issue I'm having is seeing how examples like the one above adapt to a working application with multiple views/presenters/models.

This is presumably just a simplification in order to avoid incorporating a complete IoC implementation in the sample. An MVP triad is usually represented by stand-alone (i.e.: not static, singleton, or otherwise shared) instances at runtime. In some exceptional cases, a model may be a shared instance, but this is usually the exception rather than the rule, and it's generally only the case for read-only forms or controls.

Can C++/CX simplify my (non-WinRT) WPF application?

7 votes

C++/CX seems to make interfacing native C++ with C# FAR easier and more direct than the current method using a C++/CLI 'layer' in-between (with all the complications that entails). But can I use C++/CX OUTSIDE WinRT in a old-school WPF Desktop-style Application? Clarification: My WPF App 'wraps' an older Windows32 Application code. So I'm interopting with native c++, but it's awkward having native c++, Managed C++ and c# all in the same application..

No you cannot use C++/CX outside WinRT - it relies on the windows runtime metadata and there is no metadata for non winrt APIs.

Capturing sound from TV Card with C#

6 votes

I have written a WPF application which is capturing display and sound from TV Card from with through C# code. I can get the display from TV card, but I can't get any sound from TV Card. BTW, I'm using .NET framework 3.5 with Visual Studio 2010. My question is how can I get the sound from the TV card?

Lastly, I tried anything like below by using DirectSound library of DirectX. However, I got the following errors.

  1. The best overloaded method match for 'Microsoft.DirectX.DirectSound.Device.SetCooperativeLevel(System.Windows.Forms.Control, Microsoft.DirectX.DirectSound.CooperativeLevel)' has some invalid arguments.
  2. Argument 1: cannot convert from 'Wpfvideo.MainWindow' to 'System.Windows.Forms.Control'

Code:

private DS.Device soundDevice;
private SecondaryBuffer buffer;
private ArrayList soundlist = new ArrayList();

private void InitializeSound()
{
     soundDevice = new DS.Device();
     soundDevice.SetCooperativeLevel(this, CooperativeLevel.Priority);

    BufferDescription description = new BufferDescription();
    description.ControlEffects = false;
    buffer = new SecondaryBuffer(CaptureDeviceName, description, soundDevice);
    buffer.Play(0, BufferPlayFlags.Default);
    SecondaryBuffer newshotsound = buffer.Clone(soundDevice);
    newshotsound.Play(0, BufferPlayFlags.Default);
} 

Try this:

var windowInteropHelper = new WindowInteropHelper(this);
soundDevice = new DS.Device();
soundDevice.SetCooperativeLevel(windowInteropHelper.Handle, CooperativeLevel.Priority);

What does * mean in XAML

6 votes

What does * mean in XAML. I have a grid of width 400. And divided the grid to 3 columns. What does *.4 mean? I thought it is 40% of the space available. so thought the first 2 columns will get 40% percent each and the rest is taken by the third column. but looks like, the third column is taking 60% and the first two are getting 20% each. How does this work?

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".4*"/>
        <ColumnDefinition Width=".4*"/>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
</Grid>

enter image description here

Basically, the default is "1*", so what you have above is effectively:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="0.4*" />
    <ColumnDefinition Width="0.4*" />
    <ColumnDefinition Width="1.0*" />
</Grid.ColumnDefinitions>

The Star grid spacing (GridUnitType.Star) proportionally distributes space. In your case, you have a total of 1.8 (1.0 + 0.4 + 0.4), so the first two columns each get 22.2% (0.4/1.8) of the width allocated to them.

To get what you want, you can use:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="0.4*" />
    <ColumnDefinition Width="0.4*" />
    <ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>

This sets the total to 1.0, so each becomes a percentage.

Note that this will give exactly the same result as doing:

<Grid.ColumnDefinitions>
    <ColumnDefinition Width="40*" />
    <ColumnDefinition Width="40*" />
    <ColumnDefinition Width="20*" />
</Grid.ColumnDefinitions>

Since the total proportions are divided up by the total (100) now, still giving 40%, 40%, 20%.

Why does my ScrollViewer destroy my Grid Layout? WPF

5 votes

Problem: When adding a ScrollViwer around a Grid the Grid scaling is cancelled!

Eksampel: I have created a grid width 3 columns, the 1. coulymn should always be 2 times larger than column 2 and 3! Without the ScrollViewer this is always true, but when adding it it allows each column to decide its own size.

<Window x:Class="alternatingGridRow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="Auto" Loaded="WindowLoaded">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
    <Grid x:Name="LayoutRoot" ShowGridLines="True">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" MinHeight="23" MaxHeight="60"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Stretch" Text="sdasdasdasdsadsadasddasdck" TextWrapping="Wrap" VerticalAlignment="Top" />
            <TextBlock Foreground="Red" Grid.Column="1" HorizontalAlignment="Stretch" Text="sdasdasdasdsadsadasddasdck" TextWrapping="Wrap" VerticalAlignment="Top" />
    </Grid>
</ScrollViewer>

As you can clearly see the scaling factors are completely wrong! As the 2. column is way to large! and the 3. column is some random size...

Wrong Scaling factors

Any advice on this is well recieved.... Cheers Martin

Ok I see your point in why the column sizes a screwed.
But.. I thought of a solution as I read your posts...

As, Mohammed said, set a fixed width on my grid, well.. I want my grid to have same width as scrollviewer unless it gets to small, then I want the scrollviewer to take affect! So.. my solution is:

MinWidth="500" Width="{Binding ActualWidth, ElementName=scrollviewer}"

<Window x:Class="alternatingGridRow.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="200" Width="Auto">
<ScrollViewer x:Name="scrollviewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
    <Grid x:Name="LayoutRoot" ShowGridLines="True" MinWidth="500" Width="{Binding ActualWidth, ElementName=scrollviewer}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" MinHeight="23" MaxHeight="60"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="1*"/>
        </Grid.ColumnDefinitions>
            <TextBlock HorizontalAlignment="Stretch" Text="sdasdasdasdsadsadasddasdck" TextWrapping="Wrap" VerticalAlignment="Top" />
            <TextBlock Foreground="Red" Grid.Column="1" HorizontalAlignment="Stretch" Text="sdasdasdasdsadsadasddasdck" TextWrapping="Wrap" VerticalAlignment="Top" />
    </Grid>
</ScrollViewer>

</Window>

(Only fixed for horizontal)

Thx.

Detect system language change in WPF

5 votes

As you know, we can use following code to know when the system language change in Windows Form:

string _language = "";
InputLanguageChanged += new InputLanguageChangedEventHandler( (sender, e) =>
{
      language = InputLanguage.CurrentInputLanguage.LayoutName;
});

But, i couldn't find equivalency to InputLanguageChanged event in WPF. Could anyone please give me a solution to achieve this in WPF?

Thanks for your attention :)

You can use the code as follow to detect keyboard language change in WPF


string language = "";
System.Windows.Input.InputLanguageManager.Current.InputLanguageChanged += new InputLanguageEventHandler((sender, e) =>
{
     language = e.NewLanguage.DisplayName;
}); 

Wpf DataGrid issue

5 votes

To reproduce this issue, Add a user control, paste in the xaml below and then add an instance to a window. Finally set the window's datacontext to an instance of ADummyDataContext (also below)

When you run the application for the first time, you should get a grid with three categories each containing one cat. If you click on either of the bottom two categories and click on a cat name, a blue row will appear showing just the cat's name.

However, if you click the first row and click the cat's row, the blue row will not appear. NOTE: This only happens the first time you run the application. As soon as you click on any other cat the cat in the first category will work as expected.

<UserControl x:Class="WpfUserControls.SimpleGridControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Background="#FFE46400">
<Grid Margin="2,2,2,2">
    <Grid.RowDefinitions>
        <RowDefinition Height="26" MaxHeight="26" MinHeight="26" />
        <RowDefinition />
        <RowDefinition Height="26" MaxHeight="26" MinHeight="26" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ToolBar Grid.Row="0">
        <Button Content="Button" Name="button1" VerticalAlignment="Center" Width="75" />
        <Button Content="Button" Name="button2" VerticalAlignment="Center" Width="75" />
    </ToolBar>
    <DataGrid CanUserAddRows="False" ItemsSource="{Binding Path=KittensView}"  AutoGenerateColumns="True" Grid.Row="1"  HorizontalAlignment="Stretch" Name="dataGrid1" VerticalAlignment="Stretch">
        <DataGrid.GroupStyle>
            <GroupStyle>
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Name}" />
                        </StackPanel>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
                <GroupStyle.ContainerStyle>
                    <Style TargetType="{x:Type GroupItem}">
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type GroupItem}">
                                    <Expander>
                                        <Expander.Header>
                                            <StackPanel Orientation="Horizontal">
                                                <TextBlock Text="{Binding Path=Name}" Margin="0,0,5,0"/>
                                                <TextBlock Text="{Binding Path=ItemCount}"/>
                                                <TextBlock Text=" Items"/>
                                            </StackPanel>
                                        </Expander.Header>
                                        <ItemsPresenter />
                                    </Expander>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </GroupStyle.ContainerStyle>
            </GroupStyle>
        </DataGrid.GroupStyle>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <StackPanel Background="LightBlue" Orientation="Horizontal" >
                    <!-- <Image Height="32" Width="32" Source="/WpfUserControls;component/cat.png"></Image> -->
                    <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Height ="20" Text="{Binding Path=Name}"/>
                </StackPanel>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    <StatusBar Grid.Row="2"></StatusBar>

</Grid>
</UserControl>

And here is the data context class and a Kitten class.

    public class ADummyDataContext
{
    public List<Kitten> Kittens { get; set; } 

    public ADummyDataContext()
    {
        Kittens = new List<Kitten>
                      {
                          new Kitten {Color = "Orange", Name = "Alfie", Weight=6, Sex="Male"},
                          new Kitten {Color = "Black and White", Name = "Smudge", Weight = 4, Sex="Female"},
                          new Kitten {Color = "Grey", Name = "Charlotte", Weight = 5, Sex="Female"}
                      };
        KittensView = new ListCollectionView(Kittens);
        KittensView.GroupDescriptions.Add(new PropertyGroupDescription("Weight"));
    }

    public ListCollectionView KittensView { get; set; }
}

public class Kitten
{
    public string Name { get; set; }
    public string Color { get; set; }
    public int Weight { get; set; }
    public string Sex { get; set; }

}

I would be particularly interested to know how you go about figuring out what the problem is here.

Thanks

The problem is that the first item in the DataGrid is already selected when it's first loaded. However, it isn't really selected, it doesn't appear selected and group isn't expanded. But when you click on the first item for the first time, the DataGrid can't tell the difference since SelectedIndex was already 0. This is really annoying and I noticed similar behavior several times earlier.

As a workaround, you can unselect the first item in the Loaded event of the DataGrid

<DataGrid Loaded="dataGrid1_Loaded"
          ...>

Event handler: Notice that the SelectedIndex is 0

private void dataGrid1_Loaded(object sender, RoutedEventArgs e)
{
    DataGrid dataGrid = sender as DataGrid;
    dataGrid.SelectedItem = null;
}

WPF ListboxItem and ContextMenu

5 votes

I have code like this:

<ListBox.ItemTemplate>
    <DataTemplate>
        <StackPanel Orientation="Vertical" 
                    ContextMenuService.ShowOnDisabled="True">
            <StackPanel.ContextMenu>
                <ContextMenu>
                    <MenuItem Command="Delete" Click="DeleteEvent">      
                    </MenuItem>
                </ContextMenu>
            </StackPanel.ContextMenu>
                <TextBlock Text="{Binding EventName}">
            </TextBlock>        
        </StackPanel>
    </DataTemplate>
</ListBox.ItemTemplate>

Unfortunately It doesn't work. My context menu is disabled (it is displaying but I cannot click it because it's disabled). I've read that this problem is related to selection problem but I didn't find any solution for that. Do you have any ideas?

Firstly, something strange is that you are trying to set Command and the Click event. You should set one or the other. Maybe the fact the action is disabled is because you are setting a Command with a value of CanExecute = false;

Instead of writing a DataTemplate, you can try to set the ItemContainerStyle for the ListBoxItem like this:

<ListBox>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <Setter Property="ContextMenu">
                <Setter.Value>
                    <ContextMenu>
                        <MenuItem Header="Delete" Click="DeleteEvent"/>
                    </ContextMenu>
                </Setter.Value>
            </Setter>
            <Setter Property="Content" Value="{Binding Path=EventName}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

Here I directly set the ContextMenu of the ListBoxItem instance so it will display the menu on the right control.