Thursday, April 14, 2011

TreeViewItem.Header with Grid inside

I'm trying to make "Img" appear in the end of TreeViewItem.Header (as close to the right side of TreeView control), but no mater what I try header wide is always less than TreeView size and ofcourse "Img" appear somewhere in the middle of the control. This probably a very newbish question; I'm just starting to learn WPF.

<TreeView Grid.Row="1" Grid.ColumnSpan="2" Margin="3,3,3,3" Name="treeView1" Width="300">
    <TreeViewItem HorizontalAlignment="Stretch">
        <TreeViewItem.Header>
            <Grid HorizontalAlignment="Stretch">
                <Grid.RowDefinitions>
                    <RowDefinition  />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="30" />
                </Grid.ColumnDefinitions>

                <Label Grid.Column="0" Grid.Row="0">General</Label>
                <Label Grid.Column="1" Grid.Row="0">Img</Label>
            </Grid>
        </TreeViewItem.Header>
    </TreeViewItem>
</TreeView>
From stackoverflow
  • To achieve that you need to change the Control template of the TreeviewItem using the ItemContainerStyle of the TreeView (this is the style that gets applied to any item in the root of the treeview).

    The default TreeViewItem is not stretched, so it does not extend all the way to the right. When you set the Header, it is inside the TreeViewItem and so cannot extend past it.

    I will not post the whole style because it would be way too long.

    Here's what to do in Blend: select your TreeViewItem, right click and chose "Edit Control Parts/Edit a copy". Save the style wherever you want.

    Now, in the template, expand the stuff and locate the "Bd" element, which is a border. Change its RowSpan property to "2".

    Last, set the "HorizontalContentAlignment" property of your item to "Stretch" (either on the item or through the style if you need to apply that to several nodes).

    Your item should now be the correct width. Now, this only applies to the item you selected. If you want that to work for any item you add to the treeview, you need to change the "ItemContainerStyle" of the Treeview to the newly created style, and remove the style that Blend placed on the TreeViewItem.

    Last but not least, you need to set the ItemContainerStyle of your TreeViewItem to that same style so that its children also extend all the way, and so on and so forth.

    So in the end, with your example and a child node on the first item:

    <Grid x:Name="LayoutRoot">
    <TreeView Margin="3,3,3,3" Name="treeView1" Width="300" ItemContainerStyle="{DynamicResource TreeViewItemStyle1}">
    <TreeViewItem HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" ItemContainerStyle="{DynamicResource TreeViewItemStyle1}">
        <TreeViewItem.Header>
            <Grid HorizontalAlignment="Stretch">
                <Grid.RowDefinitions>
                    <RowDefinition  />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="30" />
                </Grid.ColumnDefinitions>
    
                <Label Grid.Column="0" Grid.Row="0">General</Label>
                <Label Grid.Column="1" Grid.Row="0">Img</Label>
            </Grid>
        </TreeViewItem.Header>
        <TreeViewItem>
      <TreeViewItem.Header>
            <Grid HorizontalAlignment="Stretch">
                <Grid.RowDefinitions>
                    <RowDefinition  />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition Width="30" />
                </Grid.ColumnDefinitions>
    
                <Label Grid.Column="0" Grid.Row="0">General</Label>
                <Label Grid.Column="1" Grid.Row="0">Img</Label>
            </Grid>
        </TreeViewItem.Header>
    </TreeViewItem>
    </TreeViewItem>
    

    The "TreeViewItemStyle1" is the style that Blend created for you.

    EDIT

    as requested, here's the full style as generated by blend and modified. It is long because it basically is a copy of the built-in style with minor modifications.

    <Style x:Key="TreeViewItemFocusVisual">
          <Setter Property="Control.Template">
           <Setter.Value>
            <ControlTemplate>
             <Rectangle/>
            </ControlTemplate>
           </Setter.Value>
          </Setter>
         </Style>
         <PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
         <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
          <Setter Property="Focusable" Value="False"/>
          <Setter Property="Width" Value="16"/>
          <Setter Property="Height" Value="16"/>
          <Setter Property="Template">
           <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
             <Border Width="16" Height="16" Background="Transparent" Padding="5,5,5,5">
              <Path Fill="Transparent" Stroke="#FF989898" x:Name="ExpandPath" Data="{StaticResource TreeArrow}">
               <Path.RenderTransform>
                <RotateTransform Angle="135" CenterX="3" CenterY="3"/>
               </Path.RenderTransform>
              </Path>
             </Border>
             <ControlTemplate.Triggers>
              <Trigger Property="IsMouseOver" Value="True">
               <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
               <Setter Property="Fill" TargetName="ExpandPath" Value="Transparent"/>
              </Trigger>
              <Trigger Property="IsChecked" Value="True">
               <Setter Property="RenderTransform" TargetName="ExpandPath">
                <Setter.Value>
                 <RotateTransform Angle="180" CenterX="3" CenterY="3"/>
                </Setter.Value>
               </Setter>
               <Setter Property="Fill" TargetName="ExpandPath" Value="#FF595959"/>
               <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF262626"/>
              </Trigger>
             </ControlTemplate.Triggers>
            </ControlTemplate>
           </Setter.Value>
          </Setter>
         </Style>
         <Style x:Key="TreeViewItemStyle1" TargetType="{x:Type TreeViewItem}">
          <Setter Property="Background" Value="Transparent"/>
          <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
          <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
          <Setter Property="Padding" Value="1,0,0,0"/>
          <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
          <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
          <Setter Property="Template">
           <Setter.Value>
            <ControlTemplate TargetType="{x:Type TreeViewItem}">
             <Grid>
              <Grid.ColumnDefinitions>
               <ColumnDefinition MinWidth="19" Width="Auto"/>
               <ColumnDefinition Width="Auto"/>
               <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>
              <Grid.RowDefinitions>
               <RowDefinition Height="Auto"/>
               <RowDefinition/>
              </Grid.RowDefinitions>
              <ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" ClickMode="Press" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/>
              <Border x:Name="Bd" SnapsToDevicePixels="true" Grid.Column="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" Grid.ColumnSpan="2">
               <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" x:Name="PART_Header" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header"/>
              </Border>
              <ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1"/>
             </Grid>
             <ControlTemplate.Triggers>
              <Trigger Property="IsExpanded" Value="false">
               <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
              </Trigger>
              <Trigger Property="HasItems" Value="false">
               <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
              </Trigger>
              <Trigger Property="IsSelected" Value="true">
               <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
               <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
              </Trigger>
              <MultiTrigger>
               <MultiTrigger.Conditions>
                <Condition Property="IsSelected" Value="true"/>
                <Condition Property="IsSelectionActive" Value="false"/>
               </MultiTrigger.Conditions>
               <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
               <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
              </MultiTrigger>
              <Trigger Property="IsEnabled" Value="false">
               <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
              </Trigger>
             </ControlTemplate.Triggers>
            </ControlTemplate>
           </Setter.Value>
          </Setter>
         </Style>
    
    Sergej Andrejev : Could you post the style, or at least a setter. I don't find Bd element you are talking about
  • See this post for two samples. I just created these today.

    http://stackoverflow.com/questions/664632/highlight-whole-treeviewitem-line-in-wpf

    Sergej Andrejev : This was useful too, but Denis was first

Platform independent file locking?

I'm running a very computationally intensive scientific job that spits out results every now and then. The job is basically to just simulate the same thing a whole bunch of times, so it's divided among several computers, which use different OSes. I'd like to direct the output from all these instances to the same file, since all the computers can see the same filesystem via NFS/Samba. Here are the constraints:

  1. Must allow safe concurrent appends. Must block if some other instance on another computer is currently appending to the file.
  2. Performance does not count. I/O for each instance is only a few bytes per minute.
  3. Simplicity does count. The whole point of this (besides pure curiosity) is so I can stop having every instance write to a different file and manually merging these files together.
  4. Must not depend on the details of the filesystem. Must work with an unknown filesystem on an NFS or Samba mount.

The language I'm using is D, in case that matters. I've looked, there's nothing in the standard lib that seems to do this. Both D-specific and general, language-agnostic answers are fully acceptable and appreciated.

From stackoverflow
  • I don't know D, but I thing using a mutex file to do the jobe might work. Here's some pseudo-code you might find useful:

    do {
      // Try to create a new file to use as mutex.
      // If it's already created, it will throw some kind of error.
      mutex = create_file_for_writing('lock_file');
    } while (mutex == null);
    
    // Open your log file and write results
    log_file = open_file_for_reading('the_log_file');
    write(log_file, data);
    close_file(log_file);
    
    close_file(mutex);
    // Free mutex and allow other processes to create the same file.
    delete_file(mutex);
    

    So, all processes will try to create the mutex file but only the one who wins will be able to continue. Once you write your output, close and delete the mutex so other processes can do the same.

    CyberShadow : You must have missed the part where he said he needs synchronization between different computers.
    Jiri Klouda : And this solution will not work over NFS as he requested.
    Seb : Why wouldn´t this work? I don´t mean writing a file locally in each computer but in a single location for all of them.
  • Over NFS you face some problems with client side caching and stale data. I have written an OS independent lock module to work over NFS before. The simple idea of creating a [datafile].lock file does not work well over NFS. The basic idea to work around it is to create a lock file [datafile].lock which if present means file is NOT locked and a process that wants to acquire a lock renames the file to a different name like [datafile].lock.[hostname].[pid]. The rename is an atomic enough operation that works well enough over NFS to guarantee exclusivity of the lock. The rest is basically a bunch of fail safe, loops, error checking and lock retrieval in case the process dies before releasing the lock and renaming the lock file back to [datafile].lock

  • The classic solution is to use a lock file, or more accurately a lock directory. On all common OSs creating a directory is an atomic operation so the routine is:

    • try to create a lock directory with a fixed name in a fixed location
    • if the create failed, wait a second or so and try again - repeat until success
    • write your data to the real data file
    • delete the lock directory

    This has been used by applications such as CVS for many years across many platforms. The only problem occurs in the rare cases when your app crashes while writing and before removing the lock.

  • Lock File with a twist

    Like other answers have mentioned, the easiest method is to create a lock file in the same directory as the datafile.

    Since you want to be able to access the same file over multiple PC the best solution I can think of is to just include the identifier of the machine currently writing to the data file.

    So the sequence for writing to the data file would be:

    1. Check if there is a lock file present

    2. If there is a lock file, see if I'm the one owning it by checking that its content has my identifier.
      If that's the case, just write to the data file then delete the lock file.
      If that's not the case, just wait a second or a small random length of time and try the whole cycle again.

    3. If there is no lock file, create one with my identifier and try the whole cycle again to avoid race condition (re-check that the lock file is really mine).

    Along with the identifier, I would record a timestamp in the lock file and check whether it's older than a given timeout value.
    If the timestamp is too old, then assume that the lock file is stale and just delete it as it would mea one of the PC writing to the data file may have crashed or its connection may have been lost.

    Another solution

    If you are in control the format of the data file, could be to reserve a structure at the beginning of the file to record whether it is locked or not.
    If you just reserve a byte for this purpose, you could assume, for instance, that 00 would mean the data file isn't locked, and that other values would represent the identifier of the machine currently writing to it.

    Issues with NFS

    OK, I'm adding a few things because Jiri Klouda correctly pointed out that NFS uses client-side caching that will result in the actual lock file being in an undetermined state.

    A few ways to solve this issue:

    • mount the NFS directory with the noac or sync options. This is easy but doesn't completely guarantee data consistency between client and server though so there may still be issues although in your case it may be OK.

    • Open the lock file or data file using the O_DIRECT, the O_SYNC or O_DSYNC attributes. This is supposed to disable caching altogether.
      This will lower performance but will ensure consistency.

    • You may be able to use flock() to lock the data file but its implementation is spotty and you will need to check if your particular OS actually uses the NFS locking service. It may do nothing at all otherwise.
      If the data file is locked, then another client opening it for writing will fail.
      Oh yeah, and it doesn't seem to work on SMB shares, so it's probably best to just forget about it.

    • Don't use NFS and just use Samba instead: there is a good article on the subject and why NFS is probably not the best answer to your usage scenario.
      You will also find in this article various methods for locking files.

    • Jiri's solution is also a good one.

    Basically, if you want to keep things simple, don't use NFS for frequently-updated files that are shared amongst multiple machines.

    Something different

    Use a small database server to save your data into and bypass the NFS/SMB locking issues altogether or keep your current multiple data files system and just write a small utility to concatenate the results.
    It may still be the safest and simplest solution to your problem.

    Jiri Klouda : This solution, while working fine on single computer, will run into race conditions because of NFS client side caching.
    janneb : Note that NFSv4 fixes many of the problems with older versions of the protocol.
  • Why not just build a simple server which sits between the file and the other computers?

    Then if you ever wanted to change the data format, you would only have to modify the server, and not all of the clients.

    In my opinion building a server would be much easier than trying to use a Network file system.

    Jiri Klouda : Or just use a database and store the data in a proper database and locking problems solved.
    dsimcha : I don't have a database configured and I don't want to configure one just to solve such a simple problem.

Configuring transport security for WCF

I have a windows service that hosts a WCF service, and a webservice on a different machine acting as a client. I have the nettcpbinding set to Transport security using Windows authentication. Am I correct to assume that the windows user the webservice is running under must have permission to access the WCF service on the other machine? If the webservice is running under NetworkService, is it possible to use it or do i need to setup a new user for it to use?

From stackoverflow
  • See http://msdn.microsoft.com/en-us/library/ms684272(VS.85).aspx for good info on networkservice. What will happen is that your WCF client will attempt to authenticate as domain\computername$ to the machine hosting the service. I personally prefer to have a specific identity for auditing purposes.

    Jesse Weigert : It's better to run as network service because it doesn't require maintaining passwords on the network. Machine account passwords change every 30 days, network account passwords tend to expire under domain policies and need to be manually changed.
  • Yes, you'll need to setup another user. Network service is a local user and will not exist on the WCF hosting machine. (Well it does, but it's got a different password and so is not shared)

    You have a couple of choices - if both machines are in the domain you can run the web application pool as a domain user, or if you're in a workgroup you can create the same username/password combination on both machines and configure the web site to run under that account. In either case you need to assign the right privileges to the new account by issuing

    aspnet_regiis -ga MachineName\AccountName
    

    If you are in a domain and kerberos authentication then you will also need to setup an SPN for the new user account

    setspn -A HTTP/webservername domain\customAccountName
    setspn -A HTTP/webservername.fullyqualifieddomainname domain\customAccountName
    

Handling ObjectDisposedException correctly in an IDisposable class hierarchy

When implementing IDisposable correctly, most implementations, including the framework guidelines, suggest including a private bool disposed; member in order to safely allow multiple calls to Dispose(), Dispose(bool) as well as to throw ObjectDisposedException when appropriate.

This works fine for a single class. However, when you subclass from your disposable resource, and a subclass contains its own native resources and unique methods, things get a little bit tricky. Most samples show how to override Dipose(bool disposing) correctly, but do not go beyond that to handling ObjectDisposedException.

There are two questions that I have in this situation.


First:

The subclass and the base class both need to be able to track the state of disposal. There are a couple of main options I know of -

  • 1) Declare private bool disposed; in both classes. Each class tracks its own this.disposed, and throws as needed.

  • 2) Use protected bool Disposed { get; private set; } instead of a field. This would let the subclass check the disposed state.

  • 3) Provide some protected helper method to check the disposed state, and throw by pulling the current type name via reflection if the object is disposed.

The advantages as disadvantages I see to each by option are:

  • 1) This "smells" to me since it contains duplicated booleans, but seems to work fine. I often use this when subclassing other code.

  • 2) This takes out the duplicated booleans, but is not the way the design guidelines books are written, etc. This is what I typically use, though, since it keeps it a single point for state.

  • 3) This seems like the cleanest option to me, but doesn't appear in standard guidelines. It may be a little less expected of an approach than others from users of the class.

I, at one point or another, have tried using all three of these approaches. I would like to know advantages and disadvantages to the three approaches, as well as any other ideas for a cleaner, better way to handle this. What choice would you make in handling this, and why?


Second:

When throwing the ObjectDisposedException, what do you use for the name argument? I know the "typical" method call is:

throw new ObjectDisposedException(GetType().FullName);

There is a comment on this page from a Microsoft employee suggesting that implementing the concrete class's full name is the appropriate usage.

In the third option above, this would be the only meaningful choice. However, if the class implements the throwing itself, you could potentially return the name of the class that defines the method that was called. (ie: the base class could return the base class's name, not the concrete subclass)

I don't think this is a good idea - but I ran into this on some code written by somebody else. Are there advantages or disadvantages to having the name of the class implementing the method returned?

From stackoverflow
  • I typically implement the first option. Indeed, it seems to be what the design guidelines recommend. The reason isn't immediately apparent, but I consider it a good one nonetheless: any implementer of the class should have the same sort of protection against the case where the object is disposed as general consumers. In other words, it's best not to assume that whoever is implementing a derived class knows precisely when they can call a certain method, whose successful execution may or may not depend on whether the object has already been disposed or not (though ideally this should be documented via XML comments anyway).

    Regarding your second question, I would again stick with the recommended practice of passing GetType().FullName, especially since it's used in the core .NET framework. Even if you think alternative methods are more appropiate, I think it's best to stick to the method used in the .NET framework for the sake of consistency.

    To conclude: as with all guidelines, it's clearly up to you how you want to implement a certain design feature, though unless you have a particularly good reason it's highly advisable just to stick with them. In both these situations, it probably wouldn't do a great deal of harm to utilise some of the alternatives you suggested in your post, so long as they are used consistently and preferably documented to the user.

  • Declare private bool disposed; in both classes. Each class tracks its own this.disposed, and throws as needed.

    It is the practical solution when you are unable to modify the base class.

    Use protected bool Disposed { get; private set; } instead of a field. This would let the subclass check the disposed state.

    Why not make it public and call it IsDisposed instead? Then you would be doing the same thing as System.Windows.Forms.Control. This is a good solution when you can modify the base class.

    you could potentially return the name of the class that defines the method

    No. The example code you referenced used "GetType().FullName". This is always the name of the most derived type, not the type that implements the particular method.

    Reed Copsey : GetType().FullName will always return the concrete type. I was saying that if you implement bool disposed in each class, individually, you don't HAVE to do that - you can return something else (like the name of the class containing the method).

NSMutableArray as @property with readonly

Suppose I have something like this:

@property (readonly) NSMutableArray *someArray;

Can I modify [obj someArray] even though the @property is set to readonly?

From stackoverflow
  • Yes, you can modify its contents. The readonly only applies to the pointer itself - in that way, it is not like C++'s const.

    Basically, saying "readonly" just means "don't translate a.someArray = foo into [a setSomeArray:foo]". That is, no setter is created.

    (Of course, if you wanted to prevent modification, you'd just use an NSArray instead.)

    Matt Gallagher : You mean C's "const". Quick point about C... it depends what side of the asterisk the "const" is on. The readonly property here IS like NSMutableArray * const someArray; but NOT like const NSMutableArray *someArray; http://en.wikipedia.org/wiki/Const-correctness
    Jesse Rusak : @Matt - Good point.
  • The contents of someArray are modifiable, although the property is not (i.e. a call cannot change the value of the someArray instance variable by assigning to the property). Note, this is different from the semantics of C++'s const. If you want the array to be actually read-only (i.e. unmodifiable by the reader), you need to wrap it with a custom accessor. In the @interface (assuming your someArray property)

    @property (readonly) NSArray *readOnlyArray;
    

    and in the @implementation

    @dynamic readOnlyArray;
    
    + (NSSet*)keyPathsForValuesAffectingReadOnlyArray {
      return [NSSet setWithObject:@"someArray"];
    }
    - (NSArray*)readOnlyArray {
      return [[[self someArray] copy] autorelease];
    }
    

    Note that the caller will still be able to mutate the state of objects in the array. If you want to prevent that, you need to make them immutable on insertion or perform a depp-copy of the array in the readOnlyArray accessor.

MySQL FULLTEXT Search Across >1 Table

As a more general case of this question because I think it may be of interest to more people...What's the best way to perform a fulltext search on two tables? Assume there are three tables, one for programs (with submitter_id) and one each for tags and descriptions with object_id: foreign keys referring to records in programs. We want the submitter_id of programs with certain text in their tags OR descriptions. We have to use MATCH AGAINST for reasons that I won't go into here. Don't get hung up on that aspect.

programs
  id
  submitter_id
tags_programs
  object_id
  text
descriptions_programs
  object_id
  text

The following works and executes in a 20ms or so:

SELECT p.submitter_id
FROM programs p
WHERE p.id IN
    (SELECT t.object_id
    FROM titles_programs t
    WHERE MATCH (t.text) AGAINST ('china')
UNION ALL
    SELECT d.object_id
    FROM descriptions_programs d
    WHERE MATCH (d.text) AGAINST ('china'))

but I tried to rewrite this as a JOIN as follows and it runs for a very long time. I have to kill it after 60 seconds.

SELECT p.id 
FROM descriptions_programs d, tags_programs t, programs p
WHERE (d.object_id=p.id AND MATCH (d.text) AGAINST ('china'))
OR    (t.object_id=p.id AND MATCH (t.text) AGAINST ('china'))

Just out of curiosity I replaced the OR with AND. That also runs in s few milliseconds, but it's not what I need. What's wrong with the above second query? I can live with the UNION and subselects, but I'd like to understand.

From stackoverflow
  • Join after the filters (e.g. join the results), don't try to join and then filter.

    The reason is that you lose use of your fulltext index.

    Clarification in response to the comment: I'm using the word join generically here, not as JOIN but as a synonym for merge or combine.

    I'm essentially saying you should use the first (faster) query, or something like it. The reason it's faster is that each of the subqueries is sufficiently uncluttered that the db can use that table's full text index to do the select very quickly. Joining the two (presumably much smaller) result sets (with UNION) is also fast. This means the whole thing is fast.

    The slow version winds up walking through lots of data testing it to see if it's what you want, rather than quickly winnowing the data down and only searching through rows you are likely to actually want.

    Doug Kaye : Is the syntax for that any different than the first example?
    Doug Kaye : I don't follow, Markus. (a) How would you write 'join after the filters?' and (b) 'you lose use of your fulltext index.???
  • If you join both tables you end up having lots of records to inspect. Just as an example, if both tables have 100,000 records, fully joining them give you with 10,000,000,000 records (10 billion!).

    If you change the OR by AND, then you allow the engine to filter out all records from table descriptions_programs which doesn't match 'china', and only then joining with titles_programs.

    Anyway, that's not what you need, so I'd recommend sticking to the UNION way.

    Doug Kaye : Is that math correct? If I have 100,000 programs and each one has a title, why wouldn't the join of programs and tags yield just 100,000 rows? And if you also join 100,000 descriptions, don't you still have only 100,000 rows?
    Seb : If you want to match programs with titles, then match then in the join clause. If you just join them without any ON clause, then all rows are matched. Do something like FROM descriptions_programs d JOIN tags_programs t ON d.object_id = t.objecT_id JOIN programs p ON t.object_id = p.id
  • The union is the proper way to go. The join will pull in both full text indexes at once and can multiple the number of checks actually preformed.

  • Just in case you don't know: MySQL has a built in statement called EXPLAIN that can be used to see what's going on under the surface. There's a lot of articles about this, so I won't be going into any detail, but for each table it provides an estimate for the number of rows it will need to process. If you look at the "rows" column in the EXPLAIN result for the second query you'll probably see that the number of rows is quite large, and certainly a lot larger than from the first one.

    The net is full of warnings about using subqueries in MySQL, but it turns out that many times the developer is smarter than the MySQL optimizer. Filtering results in some manner before joining can cause major performance boosts in many cases.

Use reflection to set the value of a field in a struct which is part of an array of structs

At the moment my code successfully sets the value of fields/properties/arrays of an object using reflection given a path to the field/property from the root object.

e.g.

//MyObject.MySubProperty.MyProperty
SetValue('MySubProperty/MyProperty', 'new value', MyObject);

The above example would set 'MyProperty' property of the 'MyObject' object to 'new value'

I'm unable to use reflection to set a value of a field in a struct which is part of an array of structs because the struct is a value type (within an array).

Here are some test classes/structs...

public class MyClass {
        public MyStruct[] myStructArray = new MyStruct[] {
            new MyStruct() { myField = "change my value" } 
        };
        public MyStruct[] myOtherStructArray = new MyStruct[] {
            new MyStruct() { myOtherField = "change my value" }, 
            new MyStruct() { myOtherField = "change my other value" } 
        };
}

public struct MyStruct { public string myField; public string myOtherField; }

Below is how I successfully set the value of normal properties/fields and props/fields in lists...

public void SetValue(string pathToData, object newValue, object rootObject)
{
    object foundObject = rootObject;
    foreach (string element in pathToData.Split("/"))
    {
     foundObject = //If element is [Blah] then get the
                      //object at the specified list position
     //OR
        foundObject = //Else get the field/property
    }

    //Once found, set the value (this is the bit that doesn't work for
    //                           fields/properties in structs in arrays)
    FieldInf.SetValue(foundObject, newValue);
}

object myObject = new MyClass();
SetValue("/myStructArray/[0]/myField", "my new value", myObject);
SetValue("/myOtherStructArray/[1]/myOtherField", "my new value", myObject);

After that I want the myObject.myStructArray[0].myField = ''my new value" and myObject.myOtherStructArray[1].myOtherField = ''my new value"

All I need is a replacement for the 'FieldInf.SetValue(foundObject, newValue);' line

thanks in advance

From stackoverflow
  • If I had to guess, the bug is in part of the code you omitted, specifically I'd suspect that:

        foundObject = //If element is [Blah] then get the
                      //object at the specified list position
    

    is (unintentionally) setting foundObject to a copy of the object at the specified list position.

    Mark : Hi thans for answering, please see my feedback below...
  • My question continued...

    The only solution i found to a similar problem I had setting a field/property in a struct that is a field was to use...

    //GrandParentObject is myObject
    //GrandParentType is typeof(MyClass)
    //FieldIWantedToSet is the field info of myStruct.FieldIWantedToSet
    FieldInfo oFieldValueTypeInfo = GrandParentType.GetField("myStruct");
    TypedReference typedRefToValueType = TypedReference.MakeTypedReference(GrandParentObject, new FieldInfo[] { oFieldValueTypeInfo });
    FieldIWantedToSet.SetValueDirect(typedRefToValueType, "my new value");
    

    Problem is how can I use SetValueDirect on a array/list of structs, i'm guessing my old method above will not work when the structs are in an array because I cannot get the FieldInfo for the struct (because its in an array)?

  • Get the FieldInfo for the array object (not the specific element).

    If it's an array, cast it to a System.Array and use Array.SetValue to set the object's value.

    Mark : Thanks for your answer, i don't think that will work because the structure is as follows... MyObject.myStructArray[0].myField So using your method Array.SetValue
    Mark : ... would to pass in a brand new struct, i'm trying to set the value of a field in a struct thats in an array
    Reed Copsey : Yes. Whenever you have an array of structs, that's the best approach. You can copy it to a new, local struct, and only overwrite that member, then pass that back in.
    Reed Copsey : As a rule of thumb, though, typically structs should be immutable, so typically, you should avoid structs where one member can be changed. The design guidelines explain why in details...
    Mark : OK thanks. Looks like i'm catering for situations that are never going to occur in classes. PS Where are these design guidelines you speak of?
    Reed Copsey : Part of the design guidelines for .net frameworks is available on MSDN. There is a book written by 2 MS people that explains all the guidelines in detail, though. Is one I highly recommend.
    Reed Copsey : See http://www.amazon.com/Framework-Design-Guidelines-Conventions-Development/dp/0321545613/ref=sr_1_1?ie=UTF8&s=books&qid=1237751853&sr=8-1
    Mark : Cheers, i've got the book via work. Its very thorough and its good to dip into for a quick info fix while working. Any other good .NET books you could recommend?